Go, End to End
Strings, Runes, and Bytes
A Go string is an immutable sequence of bytes, conventionally (but not enforced) holding UTF-8 encoded text. Once created, a string's contents can never be modified in place, any "modification" actually builds a new string.
byte vs rune
A byte is an alias for uint8, a single 8-bit value. A rune is an alias for int32 and represents a single Unicode code point, which can take anywhere from 1 to 4 bytes to encode in UTF-8. Confusing the two is the source of almost every "why is my string indexing broken" question from newcomers.
Indexing gives you bytes, range gives you runes
s[i] accesses the i-th byte of a string, which may be in the middle of a multi-byte character. Ranging over a string with for i, r := range s instead decodes UTF-8 properly and gives you full runes, with i as the byte offset where that rune starts (which is why the indices can skip numbers for multi-byte characters).
Notice the byte offsets jump from 1 to 3, skipping 2, because 'é' takes 2 bytes. If you'd instead looped with a plain index (for i := 0; i < len(s); i++) and printed s[i], you'd get raw bytes, and printing one half of a multi-byte character as if it were a whole one produces garbage.
Building strings efficiently
Since strings are immutable, repeatedly concatenating with + in a loop reallocates a new string every time, which is quadratic in the number of concatenations for a loop of that size. strings.Builder avoids this by writing into a growable internal buffer and only producing the final string once, at the end.
A quick tour: strings, strconv, unicode
strings: searching, splitting, joining, replacing, case conversion (strings.Contains,strings.Split,strings.Join,strings.ToUpper, and many more)strconv: converting between strings and other types (strconv.Atoi,strconv.Itoa,strconv.ParseFloat,strconv.FormatBool)unicode: classifying individual runes (unicode.IsDigit,unicode.IsSpace,unicode.IsUpper)
Try it yourself: write a function that reverses a string correctly for multi-byte characters (converting to []rune first, reversing that, then converting back), and confirm it handles "héllo" without corrupting the é.