Baitai vs simboliai — len("ąžuolas") = 9
Kiek simbolių žodyje „ąžuolas"? Septyni. O ką grąžina len?
len("ąžuolas") // 9 — NE 7!
Nes len skaičiuoja baitus, ne simbolius. Kompiuteris tekstą saugo UTF-8 koduote: paprastos ASCII raidės (a, z, u) užima 1 baitą, bet lietuviškos raidės su „paukščiukais" (ą, ž, č, š, ę, ė, į, ų, ū) — 2 baitus. Žodyje „ąžuolas" yra dvi tokios raidės (ą ir ž), tad 7 simboliai = 7 + 2 papildomi baitai = 9 baitai.
Tikrą simbolių skaičių gauni dviem būdais:
utf8.RuneCountInString("ąžuolas") // 7 — importuok "unicode/utf8"
len([]rune("ąžuolas")) // 7 — []rune paverčia į simbolių sąrašą
rune Go kalboje — tai vienas simbolis (Unicode kodo taškas). []rune(s) išskaido eilutę į simbolius — ir tada indeksuoti bei skaičiuoti galima teisingai. s[0] grąžintų pirmą baitą (gali būti pusė raidės!), o []rune(s)[0] — pirmą simbolį.
Kada tai svarbu? Kai tikrini teksto ilgį (pavadinimas iki 60 simbolių), kai karpai tekstą (kad neperkirstum „ą" per pusę) arba imi „pirmą raidę". Anglišką tekstą len skaičiuoja teisingai atsitiktinai — nes ASCII raidės po 1 baitą. Bet lietuviškam — beveik visada suklystų.
strings.Builder — jungimui cikle. Kai eilutę „augini" cikle su +=, Go kaskart sukuria naują eilutę (senoji nekintama), tad N kartų — tai lėta (O(n²)). strings.Builder kaupia į vieną buferį:
var b strings.Builder
for i := 0; i < n; i++ {
b.WriteString("= ")
}
result := b.String()
Vienam įrašui skirtumo nepajusi, bet kai 8 pamokoje turėsim daug įrašų ir norėsim sujungti visą sąrašą į vieną ataskaitą — Builder bus teisingas pasirinkimas.
Patarimas. Nebijok „paukščiukų" — Go su Unicode dirba gerai, tik reikia atskirti baitus nuo simbolių. Taisyklė paprasta: rodai vartotojui ar tikrini ilgį — galvok simboliais (
[]rune,utf8.RuneCountInString). Skaitai failą ar tinklą — ten natūralu galvoti baitais.