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

huangapple go评论94阅读模式
英文:

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

问题

我正在阅读关于Go(golang)字符串的以下对话。在Go中,字符串只是指向(只读)数组和长度的指针。因此,当你将它们传递给函数时,指针作为值传递,而不是整个字符串。因此,我想到了一个问题,如果这是真的,那么为什么你还可以定义一个以*string作为参数的函数签名呢?如果字符串已经是不可变/只读的,那么你无法改变它。如果Go在内部已经这样做了,那么允许传递字符串指针的意义是什么?

英文:

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?

答案1

得分: 40

你将指向保存字符串的"object"的指针传递给它,这样你就可以将不同的字符串赋值给它。

示例:http://play.golang.org/p/Gsybc7Me-5

func ps(s *string) {
    *s = "hoo"
}
func main() {
    s := "boo"
    ps(&s)
    fmt.Println(s)
}
英文:

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)
}

答案2

得分: 9

一个原因是你可以使用指针来区分nil和零值:

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

英文:

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

答案3

得分: 2

详细说明了其他给出的示例,当将字符串作为值传递时,包含"string struct"的内存地址实际上会发生变化。

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)
}

对我来说,这样打印出来:

initial pointer: 0xc000014270
pointerPrint:    0xc000014270
valuePrint:      0xc0000142a0

字符串结构体的大小和字符串指针的大小有以下差异:

func main() {
	a := "hellooooooooooooooooooooo"
	fmt.Printf("String struct size:  %d\n", unsafe.Sizeof(a))
	fmt.Printf("String pointer size: %d\n", unsafe.Sizeof(&a))
}

对我来说,这样打印出来:

String struct size:  16 (指向实际字符串的地址指针 + 长度)
String pointer size: 8  (指向字符串结构体的地址指针)

当将字符串作为值传递时,你正在创建一个新的结构体,其中包含指向实际字符串的相同指针和其长度。所以在我的情况下,使用值时,我们复制了16个字节而不仅仅是8个字节。好处是,由于指向实际字符串的指针仍然相同,实际字符串数据不会被复制(这可能实际上相当大)。

在我的本地机器上对这两种方法进行基准测试时,使用字符串指针时性能提高了约1.2倍。这大致是我所做的(在Google Playground上似乎不起作用):https://go.dev/play/p/BAT4ANhITDe

英文:

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

huangapple
  • 本文由 发表于 2014年7月9日 06:09:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/24642311.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定