Go String
Go'da string doğası gereği değiştirilemez, salt okunur bir bayt dizisidir (byte sequence). Bayt dizisi string'in alt düzey verilerinin sıralı dizilmiş baytlardan oluştuğunu ifade eder, bu baytlar sürekli bir bellek alanı kaplar.
Değişmezler (Literals)
Daha önce string'in iki değişmez ifade yöntemi olduğunu belirtmiştik: normal string ve native string.
Normal String
Normal string "" çift tırnak ile gösterilir, kaçış karakterlerini destekler, çok satırlı yazmayı desteklemez. Aşağıda bazı normal string'ler verilmiştir:
"Bu bir normal string\n"
"abcdefghijlmn\nopqrst\t\\uvwxyz"Bu bir normal string
abcdefghijlmn
opqrst \uvwxyzNative String
Native string ters tırnak ile gösterilir, kaçış karakterlerini desteklemez, çok satırlı yazmayı destekler. Native string içindeki tüm karakterler olduğu gibi çıktılanır, yeni satır ve girintiler dahil.
`Bu bir native string, yeni satır
tab girintisi, \t tab karakteri ancak geçersiz, yeni satır
"Bu bir normal string"
bitti
`Bu bir native string, yeni satır
tab girintisi, \t tab karakteri ancak geçersiz, yeni satır
"Bu bir normal string"
bittiErişim
String doğası gereği bayt dizisi olduğu için, indeks işlemi str[i] i. baytı döndürecek şekilde tasarlanmıştır. Söz dizimi açısından slice ile aynıdır. Örneğin string'in ilk elemanına erişim:
func main() {
str := "bu bir string"
fmt.Println(str[0])
}Çıktı bayt kod değeri olur, karakter değil:
98String dilimleme:
func main() {
str := "bu bir string"
fmt.Println(string(str[0:4]))
}bu bString elemanını değiştirmeyi deneyin:
func main() {
str := "bu bir string"
str[0] = 'a' // derlenemez
fmt.Println(str)
}main.go:7:2: cannot assign to str[0] (value of type byte)String değiştirilemese de, üzerine yazılabilir:
func main() {
str := "bu bir string"
str = "bu başka bir string"
fmt.Println(str)
}bu başka bir stringDönüştürme
String bayt slice'a dönüştürülebilir, bayt slice veya bayt dizisi de string'e dönüştürülebilir. Örnek:
func main() {
str := "bu bir string"
// bayt slice'a açıkça tür dönüştürme
bytes := []byte(str)
fmt.Println(bytes)
// string'e açıkça tür dönüştürme
fmt.Println(string(bytes))
}String içeriği salt okunur ve değiştirilemez, ancak bayt slice değiştirilebilir.
func main() {
str := "bu bir string"
fmt.Println(&str)
bytes := []byte(str)
// bayt slice'ı değiştir
bytes = append(bytes, 96, 97, 98, 99)
// orijinal string'e ata
str = string(bytes)
fmt.Println(str)
}String'i bayt slice'a dönüştürdükten sonra, ikisi arasında hiçbir ilişki yoktur. Go bayt slice için yeni bir bellek alanı tahsis eder ve string'in belleğini oraya kopyalar. Bayt slice'ı değiştirmek orijinal string'i etkilemez, bu bellek güvenliği içindir.
Bu durumda, dönüştürülecek string veya bayt slice büyükse, performans maliyeti yüksek olur. Ancak unsafe kütüphanesi ile kopyasız dönüştürme gerçekleştirebilirsiniz, ancak arkasındaki güvenlik sorunlarını kendiniz üstlenmeniz gerekir. Aşağıdaki örnekte, b1 ve s1 adresi aynıdır:
func main() {
s1 := "merhaba dünya"
b1 := unsafe.Slice(unsafe.StringData(s1), len(s1))
fmt.Printf("%p %p", unsafe.StringData(s1), unsafe.SliceData(b1))
}0xe27bb2 0xe27bb2Uzunluk
String'in uzunluğu aslında karakter sayısı değil, bayt dizisinin uzunluğudur. Sadece çoğu zaman ASCII karakterlerle uğraştığımız için, her karakter tam olarak bir bayt ile ifade edilebilir, bu yüzden bayt uzunluğu ile karakter sayısı tesadüfen eşittir. String uzunluğunu hesaplamak için yerleşik len fonksiyonu kullanılır. Örnek:
func main() {
str := "bu bir string" // görünüşe göre uzunluk 16
str2 := "Bu bir string" // görünüşe göre uzunluk 7
fmt.Println(len(str), len(str2))
}16 21Çin karakterli string İngilizce string'den kısa görünse de, aslında hesaplanan uzunluk İngilizce string'den uzun. Bunun nedeni unicode kodlamasında, bir Çin karakteri çoğu durumda 3 bayt kaplar, bir İngilizce karakter sadece bir bayt kaplar. String'in ilk elemanını çıktılayarak sonucu görebilirsiniz:
func main() {
str := "bu bir string"
str2 := "Bu bir string"
fmt.Println(string(str[0]))
fmt.Println(string(str2[0]))
fmt.Println(string(str2[0:3]))
}b // harf b
B // bir Çin karakterinin "parçası" (ilk bayt) kod değeri
Bu // Çin karakteriKopyalama
Dizi slice kopyalama yöntemine benzer şekilde, string kopyalama aslında bayt slice kopyalamadır. Yerleşik copy fonksiyonu kullanılır:
func main() {
var dst, src string
src = "bu bir string"
desBytes := make([]byte, len(src))
copy(desBytes, src)
dst = string(desBytes)
fmt.Println(src, dst)
}strings.Clone fonksiyonu da kullanılabilir, ancak aslında iç uygulama neredeyse aynıdır:
func main() {
var dst, src string
src = "bu bir string"
dst = strings.Clone(src)
fmt.Println(src, dst)
}Birleştirme
String birleştirme + operatörü kullanılır:
func main() {
str := "bu bir string"
str = str + " bu bir int"
fmt.Println(str)
}Bayt slice'a dönüştürdükten sonra öğe de ekleyebilirsiniz:
func main() {
str := "bu bir string"
bytes := []byte(str)
bytes = append(bytes, "bu bir int"...)
str = string(bytes)
fmt.Println(str)
}Yukarıdaki iki birleştirme yönteminin performansı çok düşüktür, genel durumlar için kullanılabilir. Ancak daha yüksek performans gereksinimleri varsa, strings.Builder kullanılabilir:
func main() {
builder := strings.Builder{}
builder.WriteString("bu bir string ")
builder.WriteString("bu bir int")
fmt.Println(builder.String())
}bu bir string bu bir intYineleme
Bu makalenin başında belirtildiği gibi, Go'da string salt okunur bir bayt slice'tır, yani string'in bileşen birimi bayttır, karakter değil. Bu durum sıklıkla string'i yineerken karşılaşılır. Aşağıdaki kod gibi:
func main() {
str := "merhaba dünya!"
for i := 0; i < len(str); i++ {
fmt.Printf("%d,%x,%s\n", str[i], str[i], string(str[i]))
}
}Örnekte baytın ondalık ve onaltılık biçimleri çıktılandı.
109,6d,m
101,65,e
114,72,r
104,68,h
97,61,a
32,20,
100,64,d
117,75,u
110,6e,n
121,79,y
97,61,a
33,21,!Örnekteki karakterler ASCII karakterlere ait olduğu için, her karakterin ifade edilmesi için sadece bir bayt gerekir. Bu yüzden sonuç tesadüfen her bayt bir karaktere karşılık gelir. Ancak ASCII olmayan karakterler içerirse sonuç farklı olur:
func main() {
str := "merhaba dünya!"
for i := 0; i < len(str); i++ {
fmt.Printf("%d,%x,%s\n", str[i], str[i], string(str[i]))
}
}Genellikle bir Çin karakteri 3 bayt kaplar, bu yüzden aşağıdaki sonucu görebilirsiniz:
109,6d,m
101,65,e
114,72,r
104,68,h
97,61,a
32,20,
100,64,d
117,75,u
110,6e,n
121,79,y
97,61,a
33,21,!Bayt bazında yinelemek Çin karakterlerini böler, bu açıkça bozuk karakterlere neden olur. Go string'i açıkça UTF-8'i destekler. Bu durumla başa çıkmak için rune türünü kullanmanız gerekir. for range ile yineken, varsayılan yineleme birimi türü rune'dır. Aşağıdaki kod gibi:
func main() {
str := "merhaba dünya!"
for _, r := range str {
fmt.Printf("%d,%x,%s\n", r, r, string(r))
}
}Çıktı:
109,6d,m
101,65,e
114,72,r
104,68,h
97,61,a
32,20,
228, e4, ä
184, b8, ¸
150, 96,
231, e7, ç
149, 95,
140, 8c,
33,21,!rune doğası gereği int32 türünün takma adıdır. unicode karakter kümesi aralığı 0x0000 - 0x10FFFF arasındadır, maksimum sadece üç bayttır. Geçerli UTF-8 kodlamasının maksimum bayt sayısı sadece 4 bayttır. Bu yüzden int32 kullanmak doğal olarak doğrudur. Yukarıdaki örnekte string'i []rune'a dönüştürüp yinelemek de aynı mantıktadır:
func main() {
str := "merhaba dünya!"
runes := []rune(str)
for i := 0; i < len(runes); i++ {
fmt.Println(string(runes[i]))
}
}utf8 paketi altındaki araçları da kullanabilirsiniz, örneğin:
func main() {
str := "merhaba dünya!"
for i, w := 0, 0; i < len(str); i += w {
r, width := utf8.DecodeRuneInString(str[i:])
fmt.Println(string(r))
w = width
}
}Bu iki örneğin çıktısı aynıdır.
TIP
String hakkında daha fazla detay için Strings, bytes, runes and characters in Go adresini ziyaret edebilirsiniz.
