27

I want to replace the nth char in the original string. I can access the nth char from the string by using chars[i], but when I assign a value to chars[i], I get an error.

package main
import "fmt"

func main() {
  var chars = "abcdef"
  fmt.Println(string(chars[3]))
  chars[3] = "z" // is not working
}

4 Answers 4

27

Strings are immutable.

chars = chars[:3] + "z" + chars[4:]
Sign up to request clarification or add additional context in comments.

Comments

19

This is happening because chars is actually a string and is immutable. If you declared it appropriately (as a byte slice) then you can assign to it as you're attempting. Here's an example;

package main
import "fmt"

func main() {
  var chars = []byte{'a', 'b', 'c', 'd', 'e', 'f'}
  fmt.Println(string(chars[3]))
  fmt.Printf("%T\n", chars)
  chars[3] = 'z'
  fmt.Println(string(chars))
}

https://play.golang.org/p/N1sSsfIBQY

Alternately you could use reslicing as demonstrated in the other answer.

5 Comments

Thank you for the explanation and very good answer, this is what I'm looking for. but do I need to convert my string to byte array?
@PankajKhairnar yeah here's another example that does that... play.golang.org/p/M_Gb1_bVCs basically if you ahve a string s you can just do myBytes := []byte(s)
Thank you so much, it make sense now :)
@PankajKhairnar also, I left in that random fmt.Printf("%T\n", myInstance) bit, that can be useful as %T prints the type information. In this case I added it to double check the type of chars
Beware this won't work for Unicode strings as characters may use more than one byte. Use []rune instead of []byte.
4

Using the index operator [] on a string yields byte:

A string's bytes can be accessed by integer indices 0 through len(s)-1.

so the naive approach of indexing the string directly will work only if it just happens to contain only single-byte characters.

A more solid solution is to convert the string to rune slice:

func replaceAt(s string, i int, c rune) string {
    r := []rune(s)
    r[i] = c
    return string(r)
}

Which will work nicely with arbitrary UTF-8 input:

package main

import "fmt"

var chars = "abcdef"
var multibyte = "由汉字组成的一句话"

func main() {
    v := replaceAt(chars, 3, 'z')
    fmt.Println(v) // abczef

    w := replaceAt(multibyte, 3, 'z')
    fmt.Println(w) // 由汉子z成的一句话
}

func replaceAt(s string, i int, c rune) string {
    r := []rune(s)
    r[i] = c
    return string(r)
}

Playground: https://go.dev/play/p/wKtYIkIXw4Z

Comments

2

Use slice indexing to remove the character at the index, and place a new character there instead.

package main
import "fmt"

func main() {
  var chars = "abcdef"
  fmt.Println(string(chars[3]))
  chars = chars[:3] + "z" + chars[3+1:]
  fmt.Println(string(chars[3]))
}

Output:

d
z

[:3] selects everything in the slice from the beginning up until the index 3, and [3+1:] selects everything from the index (3+1) until the end of the slice. Put the character you wanted in-between the two statements and cat them all together for the effect of replacing a character at a specific index.

If you want to replace a specific character (i.e. all (or some of) the instances of the letter 'b') you can use the strings.Replace function.

1 Comment

it works for both idx == 0 and idx == len(chars) - 1. Check the playground: play.golang.org/p/6eLp1C9PX23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.