Start learning free

LESSON 57 OF 338 · STRINGS I

Accessing Characters in Go: Indexing a String

Lesson Read the full explanation

We can access positions inside a Go string with square brackets.

Indexes start at 0, so the first byte in "Avocado" is at index 0:

fruit := "Avocado"
fmt.Println(string(fruit[0])) // Output: A

Index 6 is the last position in "Avocado":

fmt.Println(string(fruit[6])) // Output: o

Go note: fruit[0] gives a byte, so we wrap it with string(...) when we want to print it as a one-character string.

Assignment
Follow the Coding Tutorial and print the first and last characters of fruit.


STEP 1 OF 2
    Ctrl + Enter to check

    GO · STRINGS I

    Accessing Characters in Go, explained

    What indexing a string gives you

    A Go string is a read-only sequence of bytes. Square brackets with an index pick one of those bytes, counting from 0. In "Avocado" the letter A is at index 0, and the last letter, o, is at index 6, because the string has 7 bytes.

    The important detail is the type of the result. fruit[0] is a byte, which is another name for uint8: a small number, not a piece of text. The byte for A is the number 65. Print it directly and you see the number:

    fruit := "Avocado"
    fmt.Println(fruit[0])         // 65
    fmt.Println(string(fruit[0])) // A
    

    Wrapping the byte in string(...) converts it to a one-character string, and that is what you print when you want to see the letter.

    Exercise step by step

    The lesson starts with fruit := "Avocado" and asks for the first and last characters.

    1. The first character. Index 0 holds it. Write fruit[0], wrap it in string(...) so it prints as a letter, and pass that to fmt.Println.
    2. The last character. A string of length 7 has valid indexes 0 to 6, so the last character is at index 6. Do the same thing with fruit[6].

    The solution in Go

    fruit := "Avocado"
    
    fmt.Println(string(fruit[0]))
    fmt.Println(string(fruit[6]))
    

    It prints each letter on its own line:

    A
    o
    

    Writing the literal 6 works for this string. For any string, the last index is len(fruit) - 1, which keeps working if the text changes. The next lessons use that form.

    Bytes, not characters

    For plain English text, one byte is one character, so indexing behaves the way you expect. Go strings are UTF-8, though, and a letter such as é takes two bytes. Indexing returns a single byte of it, not the whole letter:

    h := "héllo"
    fmt.Println(len(h))          // 6
    fmt.Println(h[1])            // 195
    fmt.Println(string(h[1]))    // Ã
    

    The byte at index 1 is only half of é, and converting it to a string produces an unrelated character. To work with letters rather than bytes, convert the string to a slice of runes first. A rune is a Unicode code point, and []rune(h) has one element per letter:

    r := []rune(h)
    fmt.Println(len(r))          // 5
    fmt.Println(string(r[1]))    // é
    

    Looping with for i, r := range h also decodes whole runes. In that loop the index i is the byte position where each rune starts, so after é at position 1 the next letter is at position 3. For this lesson, ASCII text and plain indexing are enough.

    Common mistakes

    • Printing without string(...). fmt.Println(fruit[0]) prints 65. This is the most common surprise.
    • Using index 7. The length is 7, but indexes stop at 6. Reading fruit[7] stops the program with a run-time panic (index out of range).
    • Counting from 1. The first character is at index 0, not 1.
    • Negative indexes. Go has no fruit[-1] for "the last one". A constant negative index is a compile error, and a negative index computed at run time panics. Use len(fruit) - 1.
    • Assigning to an index. fruit[0] = 'a' does not compile, because strings can't be changed in place.

    Why a number and not a character

    Go separates bytes from text on purpose. A string may contain letters from any alphabet, and a letter can span several bytes, so Go doesn't pretend that s[i] is "the i-th letter". It hands you the raw byte and leaves the decision to you. Converting with string(...) is correct here because every byte of "Avocado" is a whole ASCII letter. You can also compare a byte directly with a character literal, as in fruit[0] == 'A', which is true.

    Key takeaways

    • Indexes start at 0, and the last valid index is len(s) - 1.
    • s[i] is a byte, a number. Use string(s[i]) to print it as a letter.
    • Indexing works on bytes. For text beyond ASCII, convert to []rune or use range.
    Keep going with GoAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free