如何在Golang中更改指针切片

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

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.

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

答案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]
}

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:

确定