如何在Go中实现可resize的数组
我来自一个C + +的背景,我习惯于使用这个std::vector
类。 让我们假设我想要这些dynamic数组:
type a struct { b int c string }
这样做的标准方式是什么?
一个片段将是非常有用的
使用append()
内build
例:
type mytype struct { a, b int } func main() { a := []mytype{mytype{1, 2}, mytype{3, 4}} a = append(a, mytype{5, 6}) }
关于追加的更多信息,请参阅规范 。
Go Slice包含三个元素:数据,长度和容量。
s := make([]int, 0, 10)
variabless是长度为0,容量为10的整数的一部分。内置的len()和cap()函数允许您获取片的长度和容量:
len(s) == 0 cap(s) == 10
要增加切片的长度,只需重新切片即可:
s = s[0:5] // len(s) == 5 // cap(s) == 10
为了减less长度,你可以采取一个子片:
s = s[0:1] // len(s) == 1
有一些简短的方法来调用make():
a := make([]int, 10) // len(a) == cap(a) == 10 b := make([]int) // len(b) == cap(b) == 0
这一切都很好,但是如果你需要增加超出容量的分片长度呢? 要做到这一点,你需要分配一个新的切片,并将旧的切片的内容复制到新的切片。 (“复制”function是另一种内置function。)
t := make([]int, len(s), 20) copy(t, s)
Effective Go文档将此示例稍微进一步实现了一个Append函数,该函数将一个切片添加到另一个切片,并在必要时调整其大小。
切片由数组支持; 当您创build()一个特定容量的分片时,将在后台分配该容量的数组。 切片有效地成为该数组的“智能指针”。 如果将该片(或该片的子片)传递给另一个函数,则将其作为指向该相同数组的指针传递。 这使得创build子分片非常便宜 – 这是分配昂贵的后备数组。
Go标准库包含许多容器包(例如vector),无需手动pipe理切片。 使用切片来提高速度,为了方便,使用更复杂的容器类。 (说,我仍然使用切片的大部分事情。)
你可能想知道为什么你需要去解决这个问题。 毕竟,很多语言提供dynamicresize的数组作为原语。 其原因与Go的哲学有关。 语言devise者不会认为你的程序知道什么是合适的分配策略; 相反,他们给你的工具,你需要build立自己的数据结构。
这种做法的惯用方式已经改变。 内置的append()函数的添加意味着您可以像这样扩展切片:
type a struct { b int c string } func main(){ var mySlice []a mySlice = append(mySlice,a{5,"pizza"}) }
如果有空间,Append()会将给定的项目追加到切片上,如果切片不够大,则延长切片。
有关append()的更多信息,请访问http://golang.org/doc/go_spec.html#Appending_and_copying_slices
你也可以做一个切片。 这是一个知道当前长度的数组。 并可以有一个单独的电stream长度和最大容量。 请注意,为初始大小和容量传递的值不一定是常量,因此您可以创build一个函数,根据其参数构build并返回不同长度的片。
最重要的是,slice [] Int可以像数组一样被索引,并且在以这种方式使用时将返回int。
缺点是它不会自动增长超过其规定的能力。 Effective Go就是你如何去处理重新分配的一个例子。
代码将是
type mytype struct { a, b int } func main() { sl := make([]mytype, 10, 50) //slice of 10 items, max capacity 50 these do not have to be constant expressions. sl[0] = mytype{1,2} //... for i, value := range sl { // ... do stuff with value } }