Strings can't be changed in place
A Go string is immutable. Once it exists, its bytes can't be altered. That rules out the familiar way of fixing one character, assigning to an index:
name := "bndrei Chiriac"
name[0] = 'A'
This doesn't compile. The compiler reports:
cannot assign to name[0] (neither addressable nor a map index expression)
The error appears when the program is built, so nothing runs at all.
Build a new string instead
To "update" a string, build a new one from the parts you want to keep, and store it back in the variable. Slicing gives you the parts and + joins them. The variable then refers to the new string, and the old one is no longer used.
In the lesson, someone typed bndrei instead of Andrei. The fix has three steps:
- Drop the wrong letter.
name[1:]is everything from index 1 to the end, which is"ndrei Chiriac". Leaving out the end bound means "to the end of the string". - Put the right letter in front.
"A" + name[1:]joins the string"A"with that slice. - Assign the result to
name. Use=, not:=. The variable already exists, and:=would try to declare it again.
The solution in Go
name := "bndrei Chiriac"
name = "A" + name[1:]
Printing name afterwards gives:
Andrei Chiriac
Notice that "A" is in double quotes. In Go, double quotes make a string and single quotes make a rune, a single character stored as a number. Concatenating a rune and a string with + does not compile, so 'A' + name[1:] would be an error.
Other ways to get a changed string
Every function that seems to modify a string, such as strings.ToUpper or strings.ReplaceAll, returns a new string and leaves the original alone. If you ignore the return value, nothing changes.
When you need to change many characters one at a time, convert the string to a slice, edit the slice, and convert it back. A []byte works for ASCII text, and a []rune works for any text:
r := []rune("bndrei")
r[0] = 'A'
fmt.Println(string(r)) // Andrei
Both conversions copy the data, so the original string is untouched and the new string is independent of the slice.
Common mistakes
- Assigning to an index.
name[0] = 'A'never compiles. Build a new string. - Slicing from the wrong index.
name[0:]keeps the wrong first letter, andname[2:]drops a good one too. The wrong character is at index 0, so keep everything from index 1. - Using
:=for the assignment.name := ...in the same scope fails becausenameis already declared. Use plain=. - Forgetting to assign.
"A" + name[1:]on its own computes a string and throws it away, and Go reports an error for the unused expression.
Changing a letter in the middle
The same idea works at any position. To replace the character at index i, join the part before it, the new text and the part after it:
word := "cat"
i := 1
word = word[:i] + "o" + word[i+1:]
fmt.Println(word) // cot
The slice word[:i] is everything before index i, and word[i+1:] skips the old character. The lesson's case is the special case where i is 0, so the part before it is empty and can be left out.
Why Go works this way
Immutability makes strings safe to share. Two variables can refer to the same text, and a function that receives a string can't change it behind your back. The cost is that every "update" creates a new string, which is fine for a name but worth remembering when you build a long string in a loop. For that case, the strings.Builder type collects pieces without copying the text again and again.
Key takeaways
- Go strings are immutable, so you can't assign to
s[i]. - Build a new string with slicing and
+, and assign it back with=. - For character-by-character edits, convert to
[]byteor[]rune, change the slice and convert back.