Reputation: 5199
I was reading the following conversation about go (golang) strings. Strings in go are just a pointer to a (read-only) array and a length. Thus, when you pass them to a function the pointers are passed as value instead of the whole string. Therefore, it occurred to me, if that is true, then why are you even allowed to define as a function with a signature that takes *string
as an argument? If the string is already doing plus, the data is immutable/read-only, so you can't change it anyway. What is the point in allowing go to pass pointers to strings if it already does that internally anyway?
Upvotes: 21
Views: 25834
Reputation: 948
Elaborating on the other examples given here, the memory address containing the "string struct" actually changes when you pass a string as a value.
func pointerPrint(s *string) {
fmt.Printf("pointerPrint: %v\n", s)
}
func valuePrint(s string) {
fmt.Printf("valuePrint: %v\n", &s)
}
func main() {
a := "hello"
fmt.Printf("initial pointer: %v\n", &a)
pointerPrint(&a)
valuePrint(a)
}
For me this printed:
initial pointer: 0xc000014270
pointerPrint: 0xc000014270
valuePrint: 0xc0000142a0
The size of the string struct and the size of the string pointer differ as follows:
func main() {
a := "hellooooooooooooooooooooo"
fmt.Printf("String struct size: %d\n", unsafe.Sizeof(a))
fmt.Printf("String pointer size: %d\n", unsafe.Sizeof(&a))
}
Again, for me this printed:
String struct size: 16 (address pointer to actual string + length)
String pointer size: 8 (address pointer to string struct)
When passing a string as a value, you're creating a new struct, which contains the same pointer to the actual string and the length of it. So in my case, when using a value we're copying 16 bytes instead of just 8. On the plus side, since the pointer to the actual string is still the same, the actual string data will not be copied (which might actually be quite large).
When benchmarking the two on my local machine, I get about an 1.2x performance increase when using string pointers. This is approximately what I did (doesn't seem to work on Google Playground though): https://go.dev/play/p/BAT4ANhITDe
Upvotes: 4
Reputation: 1
One reason, is you can use the pointer to differentiate between nil
and zero
value:
package main
func f(s *string) {
switch {
case s == nil:
println("nil")
case *s == "":
println(`""`)
default:
println(*s)
}
}
func main() {
f(nil)
var s string
f(&s)
s = "north"
f(&s)
}
https://golang.org/ref/spec#The_zero_value
Upvotes: 9
Reputation: 99351
You pass a pointer to the "object" holding the string so that you can assign a different string to it.
Example: http://play.golang.org/p/Gsybc7Me-5
func ps(s *string) {
*s = "hoo"
}
func main() {
s := "boo"
ps(&s)
fmt.Println(s)
}
Upvotes: 43