How are strings represented in Go? What does this print?
Question 11MediumGo 1.22 to 1.25
s := "héllo"
fmt.Println(len(s))
fmt.Println(s[1])
fmt.Println(utf8.RuneCountInString(s))
for i, r := range s {
fmt.Printf("%d:%c ", i, r)
}
Output:
6
195
5
0:h 1:é 3:l 4:l 5:o
A string is an immutable, read-only sequence of bytes. Under the hood it's a two-word header: a pointer to the data and a length. The bytes don't have to be valid UTF-8, but source code literals are UTF-8. len counts bytes, and "é" takes 2 bytes (0xC3 0xA9). Indexing, s[1], gives a byte (uint8), here 195. A for range loop over a string decodes UTF-8. It yields the byte offset where each rune starts, together with the rune (int32), which is why index 2 is skipped.
Key points:
s[i] = 'x'doesn't compile, because strings are immutable. Convert to[]byteor[]runeto change one.- Slicing,
s[1:3], works on byte offsets and can cut a multi-byte character in half. - To reverse text or get the n-th character, convert to
[]rune. For graphemes like emoji with modifiers, you need a library such asgolang.org/x/textorrivo/uniseg.
More on Language Fundamentals & Types
- Q9What is the difference between a type conversion and a type assertion?
- Q10In a type switch, what is the type of the bound variable when a case lists several types, and how does
case nilbehave? - Q12What happens when you range over invalid UTF-8, and what does
string(65)produce? - Q13What does converting between
stringand[]bytecost, and how do you build strings efficiently? - Q14When are the arguments to a deferred call evaluated? What does this print?
- Q15In what order do deferred calls run, and what is wrong with using
deferinside a loop?