In one of the earlier tutorials, I shared with you how you can break up a string into a slice of substrings.
But what if your goal is just to extract a single substring from the source string?
In this case, you might want to use slicing instead. Here’s the general syntax:-
string_name[<inclusive start index>:<exclusive end index>]
Example 1: Slicing String using Explicit Start and End
Explanation to follow.
[Code]
package main
import (
"fmt"
)
func main() {
somestr := "Hello-String"
fmt.Println(somestr[0:5])
}
[Output]
Hello
[Explanation]
In this example, we’re slicing string variable somestr using a pair of square brackets. We’re also explicitly stating the start and where we want it to stop: somestr[0:5]
The first number marks the start which is index 0.
The second number marks the end which is index 5, note that this is exclusive. This means that the character at index 5 will not be included in the output substring. Only characters from index 0 to 4 (0, 1, 2, 3, 4) are included.
Example 2: Slicing String from the Start of the String to Index-N
In the previous example, we use somestr[0:5] to capture characters from index 0 to index 4.
When the first index is 0, it can be dropped without affecting the output.
For instance, somestr[:5] is equivalent to somestr[0:5].
[Code]
package main
import (
"fmt"
)
func main() {
somestr := "Hello-String"
fmt.Println(somestr[:5])
}
[Output]
Hello
Example 3: Slicing String from Index-N to the End of the String [3 Ways]
Say we’re interested in extracting “String” from the string illustrated above. The start index is 6 and we want it to stop at index 11.
Using this information, we can slice the string using somestr[6:12], we’re using 12 as the second number here instead of 11 because again, this number is non-inclusive.
However, a better way to do this is by using the length of the string as the second number: somestr[6:len(somestr)]
For those of you who like to minimize typing, this can be further simplified to just somestr[6:].
Let’s see them in action now:-
[Code]
package main
import (
"fmt"
)
func main() {
somestr := "Hello-String"
fmt.Println(somestr[6:12])
fmt.Println(somestr[6:len(somestr)])
fmt.Println(somestr[6:])
}
[Output]
String
String
String
Example 4: What Happens When Neither the Start Nor End Are Provided?
What if you call somestr[:]?
Well, it will just return an exact copy of that string.
package main
import (
"fmt"
)
func main() {
somestr := "Hello-String"
fmt.Println(somestr[:])
str2 := somestr[:]
fmt.Printf("%p vs %p\n", &somestr, &str2)
fmt.Printf("%T vs %T\n", somestr, str2)
}
[Output]
Hello-String
0xc000010250 vs 0xc000010270
string vs string
[Explanation]
As you can see from the output above, the type returned by somestr[:] is a string (and not a string pointer). The addresses of the input string and output string are also different, this means that we’ve just created a copy of the original string using the square brackets.
Discussions
1. Does changing the string returned by the square brackets change the original string?
It does not. Strings are immutable in Golang.
2. Does strings support 3-index slicing [low:high:max] in Go?
It does not. 3-index slicing doesn’t make sense for strings because, unlike slicing slices which re-use the underlying array, slicing strings create brand new strings.
[Example]
package main
import (
"fmt"
)
func main() {
somestr := "Hello-String"
fmt.Println(somestr[1:3:10])
}
[Output]
./main.go:9:28: invalid operation: 3-index slice of string