Start learning free

LESSON 59 OF 338 · STRINGS I

Updating Strings in Go: Immutability and Rebuilding

Lesson Read the full explanation

Unlike some languages, strings in Go are immutable: once a string is created, its characters cannot be changed in place. Trying to assign to a character does not compile:

name := "bndrei Chiriac"

name[0] = 'A' // compile error: cannot assign to name[0]

Instead, we build a new string from the pieces we want, using slicing and concatenation, and assign it back to the variable:

name := "bndrei Chiriac"

name = "A" + name[1:] // a new string: "A" + everything after the first character

fmt.Println(name) // Output: Andrei Chiriac

The variable now points at the new string; the old one is discarded. This is why the assignment uses = on the whole variable, not on a single character.


Assignment
Someone made a typo while saving Andrei's name. Follow the Coding Tutorial and fix the first letter by building a new string.


Hint
Look at the slicing example above if you get stuck.


STEP 1 OF 1
    Ctrl + Enter to check

    GO · STRINGS I

    Updating Strings in Go, explained

    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:

    1. 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".
    2. Put the right letter in front. "A" + name[1:] joins the string "A" with that slice.
    3. 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, and name[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 because name is 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 []byte or []rune, change the slice and convert back.
    Keep going with GoAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free