英文:
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]
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论