Start learning free

LESSON 58 OF 338 · STRINGS I

String Slicing in Go: Substrings with s[start:end]

Lesson Read the full explanation

Slicing extracts part of a string.

In Go, a slice uses the form message[start:end]. The start index is included, and the end index is excluded.

message := "Coding feels great"

firstWord := message[0:6]   // "Coding"
middleWord := message[7:12] // "feels"
lastWord := message[13:]    // "great"

If the slice goes to the end of the string, you can omit the end index, like message[13:].

Assignment
Follow the Coding Tutorial and create the three word variables from message.


STEP 1 OF 3
    Ctrl + Enter to check

    GO · STRINGS I

    String Slicing in Go, explained

    What slicing does

    A slice expression cuts a piece out of a string and gives you a new string. The form is s[start:end]. The result begins at index start and stops just before index end, so start is included and end is excluded. The length of the result is end - start.

    In the lesson, message is "Coding feels great". Its indexes run like this:

    C  o  d  i  n  g     f  e  e  l  s     g  r  e  a  t
    0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17
    

    The space between words sits at indexes 6 and 12. Each word starts right after a space, and the end bound is the index of the space after it.

    Exercise step by step

    1. The first word. Coding fills indexes 0 to 5, so the slice is message[0:6]. The end bound 6 is the first index left out, which is the space.
    2. The middle word. feels starts at index 7 and ends at index 11, so the slice is message[7:12].
    3. The last word. great starts at index 13 and runs to the end of the string. When the slice goes to the end, you can leave out the end bound: message[13:].

    The solution in Go

    message := "Coding feels great"
    
    firstWord := message[0:6]
    middleWord := message[7:12]
    lastWord := message[13:]
    

    Printing the three variables gives:

    Coding
    feels
    great
    

    Details worth knowing

    Either bound can be left out

    Without start, the slice begins at index 0. Without end, it runs to the end of the string. message[:6] is the same as message[0:6], and message[:] is the whole string.

    A slice of a string is still a string

    The type of message[0:6] is string, so you can print it, compare it or join it with +. Strings in Go can't be changed, so slicing never alters message; it makes a new value that refers to part of the original text.

    Indexes count bytes

    Both bounds are byte positions. With ASCII text, as in this lesson, one byte is one character. With text such as "héllo", where é takes two bytes, a slice can cut a letter in half and produce broken text. Convert to []rune first if you need to slice by letters.

    Out-of-range bounds stop the program

    Some languages quietly cut the slice at the end of the string. Go does not. A bound larger than the length, or a start larger than the end, makes the program panic when it runs:

    message := "I love pancakes"
    n := 20
    fmt.Println(message[:n])
    // panic: runtime error: slice bounds out of range [:20] with length 15
    

    The valid range for each bound is 0 up to len(s), and start must not be greater than end. Note that len(s) itself is allowed as a bound, because the end is excluded: s[len(s):] is an empty string.

    Common mistakes

    • Treating the end as included. message[0:6] has 6 characters, not 7. If a word comes out one letter short, the end bound is probably one too small.
    • Off-by-one at the start. The first character is at index 0, so the 8th character is at index 7.
    • Using Python-style negative bounds. message[-5:] doesn't compile in Go. Use message[len(message)-5:] for the last five characters.
    • Counting the spaces wrong. The space is a character and takes an index. Start a word right after it.

    Slicing and length together

    Because the end bound can be len(s), slicing combines well with the length. For the last word in the lesson, message[13:] and message[13:len(message)] are the same. The last five characters of any string at least five bytes long are s[len(s)-5:]. Taking the first n characters is s[:n], and dropping them is s[n:]. Together, those two slices always rebuild the original string: s[:n] + s[n:] equals s for any n from 0 to len(s).

    Checking your work

    If a slice looks wrong, print it with quotes using fmt.Printf("%q\n", firstWord). The quotes make a stray leading or trailing space visible, which is the usual sign that a bound is off by one.

    Key takeaways

    • s[start:end] includes start and excludes end.
    • Leave out start to begin at 0 and end to go to the end.
    • Bounds count bytes and must stay between 0 and len(s), or the program panics.
    Keep going with GoAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free