将切片附加到来自函数参数的切片。

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

append slice to slice from function parameter

问题

我正在尝试找出slice如何工作。请看下面的代码:

package main

import "fmt"

type ByteSlice []byte

func (p *ByteSlice) Append(data []byte) {
    slice := *p
    *p = append(slice, data...)
}

func main() {
    var a ByteSlice
    a[0] = 3
    b := []byte{4,6,7}
    a.Append(b)
    fmt.Println(b)
}

正如你在Append函数中所看到的,我试图将slice参数追加到调用中,但是我得到了以下错误:

panic: runtime error: index out of range

goroutine 16 [running]:
runtime.panic(0x4a14e0, 0x51333c)
    c:/go/src/pkg/runtime/panic.c:279 +0xe9
main.main()
    D:/Go/samples/src/method.go:16 +0x243

goroutine 17 [runnable]:
runtime.MHeap_Scavenger()
    c:/go/src/pkg/runtime/mheap.c:507
runtime.goexit()
    c:/go/src/pkg/runtime/proc.c:1445

goroutine 18 [runnable]:
bgsweep()
    c:/go/src/pkg/runtime/mgc0.c:1976
runtime.goexit()
    c:/go/src/pkg/runtime/proc.c:1445

goroutine 19 [runnable]:
runfinq()
    c:/go/src/pkg/runtime/mgc0.c:2606
runtime.goexit()
    c:/go/src/pkg/runtime/proc.c:1445
exit status 2

我在这里做错了什么?

英文:

I am trying to find out, how slice works. Look at the following code

package main

import "fmt"

type ByteSlice []byte

func (p *ByteSlice) Append(data []byte) {
	slice := *p
	*p = append(slice, data...)
}

func main() {
	var a ByteSlice
	a[0] = 3
	b := []byte{4,6,7}
	a.Append(b)
	fmt.Println(b)
}

As you can see in the append function, i try to append slice parameter into call but i've got the following error:

panic: runtime error: index out of range

goroutine 16 [running]:
runtime.panic(0x4a14e0, 0x51333c)
    c:/go/src/pkg/runtime/panic.c:279 +0xe9
main.main()
    D:/Go/samples/src/method.go:16 +0x243

goroutine 17 [runnable]:
runtime.MHeap_Scavenger()
    c:/go/src/pkg/runtime/mheap.c:507
runtime.goexit()
    c:/go/src/pkg/runtime/proc.c:1445

goroutine 18 [runnable]:
bgsweep()
    c:/go/src/pkg/runtime/mgc0.c:1976
runtime.goexit()
    c:/go/src/pkg/runtime/proc.c:1445

goroutine 19 [runnable]:
runfinq()
    c:/go/src/pkg/runtime/mgc0.c:2606
runtime.goexit()
    c:/go/src/pkg/runtime/proc.c:1445
exit status 2

What do i here wrong?

答案1

得分: 10

逐行查看我的评论:

切片只是数组的一个“视图”。

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

package main

import "fmt"

type ByteSlice []byte

func (p *ByteSlice) Append(data []byte) {
    *p = append(*p, data...)
}

func main() {
    var a ByteSlice // 只是一个指针
    // a[0] = 3 没有分配内存
    a = append(a, 3) // append 在下面分配了内存
    fmt.Println(a[0])
    b := []byte{4, 6, 7}
    a.Append(b)
    fmt.Println(a)
}

输出结果:

3
[3 4 6 7]

英文:

See my comments line by line:

a slice is just a "view" of an array.

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

package main

import "fmt"

type ByteSlice []byte

func (p *ByteSlice) Append(data []byte) {
	*p = append(*p, data...)
}

func main() {
	var a ByteSlice // is just a pointer
	// a[0] = 3  does not have memory allocate
	a = append(a, 3) // append allocates a memory underneath
	fmt.Println(a[0])
	b := []byte{4, 6, 7}
	a.Append(b)
	fmt.Println(a)
}

output

3
[3 4 6 7]

答案2

得分: 3

为了澄清之前的回答,错误是由于你尝试给a[0]赋值而导致的。

要理解为什么会出错,首先需要了解切片的结构。一个切片由三个字段组成:

  • 长度(你在切片中分配的元素数量)
  • 容量(底层数组的实际大小,可以调整大小)
  • 指向底层数组的指针。

因为切片只在逻辑上包含长度字段指定数量的元素,所以你只能访问切片中的这些元素。无法像在C语言中的数组那样访问切片中未定义的元素,这是一种安全特性。

当你初始化一个切片时,它的长度默认为0,除非你包含初始化元素或另行指定。你既没有包含初始化元素,也没有另行指定,因此a[0]超出了范围。你需要使用append函数来将3赋值给a的第一个元素,具体写法是a = append(a, 3)

这里有一篇Go博客文章更详细地讨论了这个问题

此外,正如@fabrizioM指出的,ByteSlice.Append方法中没有必要声明slice变量,你可以直接使用*p

英文:

To clarify the other answer, the error is a result of your attempt to assign a[0].

To understand why, you first need to understand the anatomy of a slice. A slice consists of three fields:

  • Its length (the number of elements you've assigned in the slice)
  • Its capacity (the actual size of the underlying array, which can be resized)
  • A pointer to the underlying array.

Because the slice only logically contains the number of elements specified by the length field, you can only access that many elements of the slice. The fact that you can't access undefined elements of the slice, like you can with an array in C, is a safety feature.

When you initialize a slice, it's length is 0 unless you include initialization elements or specify otherwise. You did neither, and a[0] is therefore out of range. You'd have to use append - a = append(a, 3), specifically - to assign the first element of a to 3.

There's a Go blog post that more fully discusses this.

Also, as @fabrizioM pointed out, there's no need to declare the slice variable in ByteSlice.Append; you can just use *p.

huangapple
  • 本文由 发表于 2014年7月18日 19:55:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/24824426.html
匿名

发表评论

匿名网友

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

确定