Charlie Parker
Charlie Parker

Reputation: 5199

What is the point of passing a pointer to a strings in go (golang)?

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

Answers (3)

Beolap
Beolap

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

Zombo
Zombo

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

OneOfOne
OneOfOne

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

Related Questions