如何在Golang中更改指针切片

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

How to change pointer slice in golang

问题

我正在尝试更好地理解Go语言。我为自己创建了一个小练习:将一个指针切片传递给一个函数并对其进行修改。

以下是我编写的代码:

  1. package main
  2. import (
  3. "fmt"
  4. "unsafe"
  5. )
  6. func main() {
  7. var data *[]byte
  8. fillData(data)
  9. fmt.Println((*data)[0:5])
  10. }
  11. func fillData(data *[]byte) {
  12. b := []byte("hello")
  13. fmt.Println(b[0:5])
  14. fmt.Println(string(b[0:5]))
  15. data = (*[]byte)(unsafe.Pointer(&b[0]))
  16. }

但是它会报错invalid memory address or nil pointer dereference。我知道在真实的代码中我不会使用这样的方式,但我只是好奇如何传递一个切片并在不返回它的情况下修改它。

链接:https://play.golang.org/p/_K5ltKKKNV

英文:

I'm trying to get a better understanding of go. I created a little exercise for myself: pass a pointer slice to a function and modify it.

This is what I came up with:

  1. package main
  2. import (
  3. "fmt"
  4. "unsafe"
  5. )
  6. func main() {
  7. var data *[]byte
  8. fillData(data)
  9. fmt.Println((*data)[0:5])
  10. }
  11. func fillData(data *[]byte) {
  12. b := []byte("hello")
  13. fmt.Println(b[0:5])
  14. fmt.Println(string(b[0:5]))
  15. data = (*[]byte)(unsafe.Pointer(&b[0]))
  16. }

But it gives an invalid memory address or nil pointer dereference error. I know I wouldn't use something like this in real code but I was just curious how to pass a slice and modify it without returning it.

https://play.golang.org/p/_K5ltKKKNV

答案1

得分: 5

当你尝试在fillData函数中更新data时,你犯了两个错误。首先,你更新了指针本身而不是指针所指向的内容。其次,data是一个空指针,因此通过该指针进行写操作将导致空指针错误。

下面是一种可能的代码编写方式。data开始作为一个零值切片,并在fillData函数中进行更新。这将从b复制切片信息(长度、容量和指向数组的指针)到*data,这意味着data将与b共享信息(包括共享底层数组)。

  1. package main
  2. import "fmt"
  3. func main() {
  4. var data []byte
  5. fillData(&data)
  6. fmt.Println(data, data[0:5])
  7. }
  8. func fillData(data *[]byte) {
  9. b := []byte("hello")
  10. *data = b[0:1]
  11. }

另一种方式是将data定义为指针,并进行更新。然后你需要将一个双指针传递给fillData函数。代码如下:

  1. package main
  2. import "fmt"
  3. func main() {
  4. var data *[]byte
  5. fillData(&data)
  6. fmt.Println((*data)[0:5])
  7. }
  8. func fillData(data **[]byte) {
  9. b := []byte("hello")
  10. *data = &b
  11. }

最后,编写这段代码的最佳方式是根本不使用指针,而是直接返回切片。与C或C++不同,很少需要使用“输出”参数来传递函数的结果。这是因为Go语言允许多个返回值。

  1. package main
  2. import "fmt"
  3. func main() {
  4. data := getData()
  5. fmt.Println(data, data[0:5])
  6. }
  7. func getData() []byte {
  8. return []byte("hello")[:1]
  9. }
英文:

When you try to update data in fillData, you make two errors. First, you update the pointer rather than what it's pointed to. Second, data is a nil pointer, so writing through that pointer will cause a nil pointer error.

Here's one possible way to write the code. data starts as a zero'ed slice, and gets updated inside fillData. This will copy the slice information (len, cap, and pointer to array) from b to *data which means that data will share information with b (importantly, including sharing the underlying array).

  1. package main
  2. import "fmt"
  3. func main() {
  4. var data []byte
  5. fillData(&data)
  6. fmt.Println(data, data[0:5])
  7. }
  8. func fillData(data *[]byte) {
  9. b := []byte("hello")
  10. *data = b[0:1]
  11. }

Another way would be to have data being a pointer, and updating it. Then you have to pass a double pointer into fillData. That would look like this:

  1. package main
  2. import "fmt"
  3. func main() {
  4. var data *[]byte
  5. fillData(&data)
  6. fmt.Println((*data)[0:5])
  7. }
  8. func fillData(data **[]byte) {
  9. b := []byte("hello")
  10. *data = &b
  11. }

Finally, the best way to write this code isn't to use pointers at all, and just return the slice. Unlike C or C++, it's rarely needed to use "output" parameters to functions. That's because go allows multiple return values.

  1. package main
  2. import "fmt"
  3. func main() {
  4. data := getData()
  5. fmt.Println(data, data[0:5])
  6. }
  7. func getData() []byte {
  8. return []byte("hello")[:1]
  9. }

huangapple
  • 本文由 发表于 2015年3月30日 06:37:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/29335766.html
匿名

发表评论

匿名网友

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

确定