关于go:切片作为参数传递的切片指针

Slicing a slice pointer passed as argument

我有以下代码:

1
2
3
4
5
6
func main() {
    var buf []byte{1, 2, 3, 4, 5}
    buf = buf[2:]
    fmt.Println(buf)
    panic(1)
}

不过,我想将指向buf字节slice的指针传递给另一个函数,并将其切片,如下所示:

1
2
3
4
5
6
7
8
9
10
func main() {
    var buf []byte{1, 2, 3, 4, 5}
    sliceArr(&buf, 2)
    fmt.Println(buf)
    panic(1)
}

func sliceArr(buf *[]byte, i int) {
    *buf = *buf[i:]
}

它给了我一个错误,我不能在sliceArr()函数的参数中使用[]byte类型作为*[]byte类型,我不能切片*[]byte类型。怎么了?默认情况下,切片不是通过引用传递的吗?我尝试在没有指针的情况下执行此操作,但它不起作用-数组正在被复制。我该怎么做?


错误cannot use type []byte as type *[]byte in argument to sliceArr()来自一个你没有发布的错误(你试图传递一个切片,而不是指向切片的指针到sliceArr())。

对于另一个错误(cannot slice type *[]byte),只需使用括号将指针取消引用分组:

1
*buf = (*buf)[i:]

你不小心从变量声明中漏掉了一个=符号。除此之外,一切都按你写的方式运作:

1
2
3
4
5
6
7
8
9
func main() {
    var buf = []byte{1, 2, 3, 4, 5}
    sliceArr(&buf, 2)
    fmt.Println(buf)
}

func sliceArr(buf *[]byte, i int) {
    *buf = (*buf)[i:]
}

输出(在游乐场上尝试):

1
[3 4 5]

注:

注意,规范规定,如果p是指向数组的指针,那么p[low:high](*p)[low:high]的简写,也就是说,指针会自动取消对您的引用。如果p是指向切片的指针,则不会自动发生这种情况,因为无法切片指针,p[low:high]无效。因此,如果指针指向切片,则必须手动取消对指针的引用。

这种偏差的原因是指向切片的指针非常罕见,因为切片已经是"just"描述符(到基础数组的连续部分),并且切片大部分时间都是在没有指针的情况下传递的,因此,如果在极少数情况下(如本例),确实需要传递指针,则需要明确处理它。另一方面,数组代表所有元素;分配或传递数组复制所有值,因此使用指向数组的指针(而不是指向切片的指针)更为常见,因此有理由对数组指针提供更多的语言支持。

还要注意,您的任务可以通过只需要一个(非指针)切片作为参数类型并返回新的切片值来完成——当然,必须在调用者处分配新的切片值(一个很好的例子是内置的append()函数)。

注2:

如果参数类型是一个切片(而不是指向切片的指针),并且传递一个切片,则不会复制底层数组,只复制切片头。但在本例中,如果您对参数进行切片(这是切片头的副本),并将新切片(切片头)重新分配给参数,那么您只是更改了参数(局部变量)的值,而不是传递的原始值(变量),这就是它无法工作的原因。

有关切片的详细信息,请阅读以下日志:

去切片:使用和内部

数组、片(和字符串):"append"的机制