英文:
How to change pointer slice in golang
问题
我正在尝试更好地理解Go语言。我为自己创建了一个小练习:将一个指针切片传递给一个函数并对其进行修改。
以下是我编写的代码:
package main
import (
"fmt"
"unsafe"
)
func main() {
var data *[]byte
fillData(data)
fmt.Println((*data)[0:5])
}
func fillData(data *[]byte) {
b := []byte("hello")
fmt.Println(b[0:5])
fmt.Println(string(b[0:5]))
data = (*[]byte)(unsafe.Pointer(&b[0]))
}
但是它会报错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:
package main
import (
"fmt"
"unsafe"
)
func main() {
var data *[]byte
fillData(data)
fmt.Println((*data)[0:5])
}
func fillData(data *[]byte) {
b := []byte("hello")
fmt.Println(b[0:5])
fmt.Println(string(b[0:5]))
data = (*[]byte)(unsafe.Pointer(&b[0]))
}
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.
答案1
得分: 5
当你尝试在fillData函数中更新data时,你犯了两个错误。首先,你更新了指针本身而不是指针所指向的内容。其次,data是一个空指针,因此通过该指针进行写操作将导致空指针错误。
下面是一种可能的代码编写方式。data开始作为一个零值切片,并在fillData函数中进行更新。这将从b复制切片信息(长度、容量和指向数组的指针)到*data,这意味着data将与b共享信息(包括共享底层数组)。
package main
import "fmt"
func main() {
var data []byte
fillData(&data)
fmt.Println(data, data[0:5])
}
func fillData(data *[]byte) {
b := []byte("hello")
*data = b[0:1]
}
另一种方式是将data定义为指针,并进行更新。然后你需要将一个双指针传递给fillData函数。代码如下:
package main
import "fmt"
func main() {
var data *[]byte
fillData(&data)
fmt.Println((*data)[0:5])
}
func fillData(data **[]byte) {
b := []byte("hello")
*data = &b
}
最后,编写这段代码的最佳方式是根本不使用指针,而是直接返回切片。与C或C++不同,很少需要使用“输出”参数来传递函数的结果。这是因为Go语言允许多个返回值。
package main
import "fmt"
func main() {
data := getData()
fmt.Println(data, data[0:5])
}
func getData() []byte {
return []byte("hello")[:1]
}
英文:
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).
package main
import "fmt"
func main() {
var data []byte
fillData(&data)
fmt.Println(data, data[0:5])
}
func fillData(data *[]byte) {
b := []byte("hello")
*data = b[0:1]
}
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:
package main
import "fmt"
func main() {
var data *[]byte
fillData(&data)
fmt.Println((*data)[0:5])
}
func fillData(data **[]byte) {
b := []byte("hello")
*data = &b
}
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.
package main
import "fmt"
func main() {
data := getData()
fmt.Println(data, data[0:5])
}
func getData() []byte {
return []byte("hello")[:1]
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论