从切片(slice)转换为数组(array)?

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

Converting from slice to array?

问题

我想知道是否有一种方法可以将适当大小的切片传递给期望数组的函数?

例如,我是否可以这样做的原因是什么?

func p(arr [4]int) {
    for _, v := range arr {
        fmt.Print(v)
    }
}

func main() {
    data := make([]int, 10)
    for i, _ := range data {
	    data[i] = i
    }

    p(data[0:4]) // 错误
}

我知道我可以创建一个副本:

arr := [4]int{}
copy(arr[:], data)
p(arr)

但这不是创建一个不必要的副本吗?(因为我猜测栈上可能还需要另一个arr的副本)

英文:

I'm wondering whether there is a way to pass a slice of the appropriate size to a function that is expecting an array?

For example, is there a reason I shouldn't be allowed to do the following?

func p(arr [4]int) {
    for _, v := range arr {
        fmt.Print(v)
    }
}

func main() {
    data := make([]int, 10)
    for i, _ := range data {
	    data[i] = i
    }

    p(data[0:4]) // error
}

I know that I can just create a copy:

arr := [4]int{}
copy(arr[:], data)
p(arr)

But isn't that just creating an unnecessary copy? (since I'm guessing that another copy of arr will have to be made on the stack)

答案1

得分: 3

例如,我不被允许执行以下操作的原因是什么?

是的,有原因。[4]int 只是一个包含四个整数的平面序列。当你将它传递给函数时,它们会被复制,所以函数内部的修改不会影响原始值。下面的代码两次打印出 1 2 3 4

func change(arr [4]int) {
    arr[1] = 100
}

func prn(arr [4]int) {
    for _, v := range arr {
        print(v, " ")
    }
    println()
}

func main() {
    x := [4]int{1, 2, 3, 4}
    prn(x)
    change(x)
    prn(x)
}

然而,切片是指向某个大小为 capacity 的数组的指针,以及一个 length - 两个指针大小的数字。当你将切片传递给函数时,实际上是传递了对底层数组的 引用,所以你可以在函数内部对其进行修改。下面的程序先打印出 1 2 3 4,然后打印出 1 100 3 4

func change(arr []int) {
    arr[1] = 100
}

func prn(arr []int) {
    for _, v := range arr {
        print(v, " ")
    }
    println()
}

func main() {
    x := []int{1, 2, 3, 4}
    prn(x)
    change(x)
    prn(x)
}

因此,实际上切片和数组的内部表示是不同的,不能互相替代。你必须将切片内容复制到另一个数组中。

当然,从技术上讲,Go 语言没有任何困难阻止它自动进行这种转换(隐式创建一个数组,并将切片内容复制到其中,并将其传递给函数)。然而,Go 语言设计者有意决定尽可能避免隐式转换。如果你真的需要这个操作,你可以自己做,这并不难。

英文:

> For example, is there a reason I shouldn't be allowed to do the
> following?

Yes, there is. [4]int is just a flat sequence of four integers. When you pass it to the function, they are copied, so modifications inside a function won't affect original value. The following code prints 1 2 3 4 both times.

func change(arr [4]int) {
    arr[1] = 100
}

func prn(arr [4]int) {
    for _, v := range arr {
        print(v, " ")
    }
    println()
}

func main() {
    x := [4]int{1, 2, 3, 4}
    prn(x)
    change(x)
    prn(x)
}

However, a slice is a pointer to an array of some size (called capacity of the slice) and a length - two pointer-sized numbers. When you pass a slice to a function, you essentially pass a reference to the underlying array, so you can change it inside the function. The following program prints 1 2 3 4 and then 1 100 3 4:

func change(arr []int) {
    arr[1] = 100
}

func prn(arr []int) {
    for _, v := range arr {
        print(v, " ")
    }
    println()
}

func main() {
    x := []int{1, 2, 3, 4}
    prn(x)
    change(x)
    prn(x)
}

So, in fact, internal representation of slices and arrays are different, and one cannot be used instead of another and vice versa. You have to copy slice contents to another array.

Of course, there are no technical difficulties which prevent Go from doing such conversion automatically (create an array implicitly and copy slice contents to it and pass it to the function). However, Go language designers made deliberate decision to abstain from implicit conversions as much as possible. If you really need this operation, you can do it yourself, it is not that hard.

huangapple
  • 本文由 发表于 2013年11月17日 13:34:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/20027599.html
匿名

发表评论

匿名网友

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

确定