如何将切片转换为固定大小的数组?

55

我想将一个固定大小的数组从一个切片中转换:

func gen(bricks []Brick) {
    if len(bricks) == 16 {
        if check(Sculpture{bricks}) {
            var b [16]Brick = bricks[0:16];
        }
     }
}

但这会导致:

 cannot use bricks[0:16] (type []Brick) as type [16]Brick in assignment

如何将一个切片转换为固定大小的数组?

2个回答

116

编辑:截至Go 1.17+,您可以尝试使用新的支持切片转数组的转换功能,https://tip.golang.org/ref/spec#Conversions_from_slice_to_array_pointer

s := make([]byte, 2, 4)
s0 := (*[0]byte)(s)      // s0 != nil
s1 := (*[1]byte)(s[1:])  // &s1[0] == &s[1]
s2 := (*[2]byte)(s)      // &s2[0] == &s[0]
s4 := (*[4]byte)(s)      // panics: len([4]byte) > len(s)

针对Go 1.16及以下版本的以前的回答:

您需要使用copy

slice := []byte("abcdefgh")

var arr [4]byte

copy(arr[:], slice[:4])

fmt.Println(arr)

正如Aedolon所指出的,您也可以直接使用

copy(arr[:], slice)

作为复制操作,它总是只会复制 srcdst中较小的长度。


13
这是正确的,只需稍作修改:您不需要 copy(arr[:], slice[:4])copy(arr[:],slice)就足够了。copy自动将自己限制在给定切片中较小的那个。 - LemurFromTheId
@Aedolon 谢谢你的提示,已经添加到答案中了。 - Stephan Dollberg
真的是个很好的回答。 - Shudipta Sharma
注意,从Golang 1.17开始,您可以使用https://tip.golang.org/ref/spec#Conversions_from_slice_to_array_pointer。 - Chris Smowton
1
@ChrisSmowton 请将那个编辑到我的答案中,或者发布一个新的答案,如果有更新的方法,那么应该是一个正式的答案而不仅仅是一个评论。 - Stephan Dollberg
@ChrisSmowton 请注意,切片转数组的转换实际上只适用于go1.20+,任何尝试在之前的版本上进行转换都会导致此错误:cannot convert ab (variable of type []int) to type [4]int: conversion of slices to arrays requires go1.20 or later (-lang was set to go1.18; check go.mod) - undefined

2
我找到了一种解决问题的方法,不需要分配更多的空间 - 定义一个与切片相同结构的新结构体并接收unsafe.Pointer。
type MySlice struct {
    Array unsafe.Pointer
    cap   int
    len   int
}
func main(){
    a := []byte{1, 2, 3, 4}
    fmt.Printf("a before %v, %p\n", a, &a)
    b := (*MySlice)(unsafe.Pointer(&a))
    c := (*[4]byte)(b.Array)
    fmt.Printf("c before %v, %T, %p\n", *c, *c, c)
    a[1] = 5
    fmt.Printf("c after %v, %p\n", *c, c)
    fmt.Printf("a after %v, %p\n", a, &a)
}

结果如下所示: 结果

这个例子很容易被破解。请看这里:https://play.golang.org/p/iSq4Q9XrRQv - Jonathan Hall
1
另外,请不要粘贴文本图片。 - Jonathan Hall
3
如果你真的需要这样做,不要使用自己的切片头,而是直接转换数据:https://play.golang.org/p/3oNob6k5ynx - JimB
1
@JimB 谢谢。但如果您更改了 i 的任何元素,x 的值将不会改变。这似乎是一份深拷贝。 - Yiheng
@Yiheng:是的,因为数组本身就是值,所以赋值操作本身就是一次复制。如果你不想要复制,就需要使用指针,但这种情况下,为什么不一开始就使用切片呢?https://play.golang.org/p/kF3_46UDbJN - JimB
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接