Skip to content

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:

go
"Bu bir normal string\n"
"abcdefghijlmn\nopqrst\t\\uvwxyz"
Bu bir normal string
abcdefghijlmn
opqrst  \uvwxyz

Native 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.

go
`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"

        bitti

Eriş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:

go
func main() {
   str := "bu bir string"
   fmt.Println(str[0])
}

Çıktı bayt kod değeri olur, karakter değil:

98

String dilimleme:

go
func main() {
   str := "bu bir string"
   fmt.Println(string(str[0:4]))
}
bu b

String elemanını değiştirmeyi deneyin:

go
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:

go
func main() {
   str := "bu bir string"
   str = "bu başka bir string"
   fmt.Println(str)
}
bu başka bir string

Dö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:

go
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.

go
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:

go
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 0xe27bb2

Uzunluk

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:

go
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:

go
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 karakteri

Kopyalama

Dizi slice kopyalama yöntemine benzer şekilde, string kopyalama aslında bayt slice kopyalamadır. Yerleşik copy fonksiyonu kullanılır:

go
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:

go
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:

go
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:

go
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:

go
func main() {
   builder := strings.Builder{}
   builder.WriteString("bu bir string ")
   builder.WriteString("bu bir int")
   fmt.Println(builder.String())
}
bu bir string bu bir int

Yineleme

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:

go
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:

go
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:

go
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:

go
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:

go
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.

Golang by www.golangdev.cn edit