mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-11 22:53:43 +08:00
add 07.2.md, 07.3.md, 07.4.md, 07.5.md
This commit is contained in:
251
eBook/07.2.md
Normal file
251
eBook/07.2.md
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
#7.2 分片
|
||||||
|
## 7.2.1 概念
|
||||||
|
slice是对数组一个连续片段的引用(该数组我们称之为相关数组,通常是匿名的),所以slice是一个引用类型(因此更类似于C/C++中的数组类型,或者Python中的list类型)。这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。需要注意的是,终止索引标识的项不包括在slice内。Slice提供了一个相关数组的动态窗口。
|
||||||
|
|
||||||
|
Slice是可索引的,并且可以由len()方法获取长度。
|
||||||
|
|
||||||
|
给定项的slice索引可能比相关数组的相同元素的索引小。和数组不同的是,slice的长度可以在运行时修改,最小为0最大为相关数组的长度:slice是一个`长度可变的数组`。
|
||||||
|
|
||||||
|
slice提供了计算容量的方法cap()可以测量slice最长可以达到多少:它等于slice的长度 + 数组除slice之外的长度。如果s是一个slice,cap就是从s[0]到数组末尾的数组长度。slice的长度永远不会超过它的容量,所以对于slice s来说该不等式永远成立: 0 <= len(s) <= cap(s)
|
||||||
|
|
||||||
|
多个slice如果表示同一个数组的片段,它们可以共享数据;因此一个slice和相关数组的其他slice是共享存储的,相反,不同的数组总是代表不同的存储。数组实际上是slice的构建块。
|
||||||
|
|
||||||
|
`优点: ` 因为slice是引用,所以它们不需要使用额外的内存并且比使用数组更有效率,所以在Go代码中slice比数组更常用。
|
||||||
|
|
||||||
|
声明slice的格式是: var identifier []type 不需要说明长度
|
||||||
|
|
||||||
|
一个slice在未初始化之前默认为nil,长度为0。
|
||||||
|
|
||||||
|
slice的初始化格式是: var slice1 []type = arr1[start:end]
|
||||||
|
|
||||||
|
这表示slice1是由数组arr1从start索引到end-1索引之间的元素构成的子集(切分数组,start:end被称为slice表达式)。所以slice1[0]就等于arr1[start]。这可以在arr1被填充前就定义好。
|
||||||
|
|
||||||
|
如果某个人写: var slice1 []type = arr1[:]那么slice1就等于完整的arr1数组(所以这种表示方式是arr1[0:len(arr1)]的一种缩写)。另外一种表述方式是:slice1 = &arr1。
|
||||||
|
|
||||||
|
arr1[2:]和arr1[2:len(arr1)]相同,都包含了数组从第二个到最后的所有元素。
|
||||||
|
|
||||||
|
arr1[:3]和arr1[0:3]相同,包含了从第一个到第三个元素(不包括第三个)。
|
||||||
|
|
||||||
|
如果你想去掉slice1的最后一个元素,只要 slice1 = slice1[:len(slice1)-1]
|
||||||
|
|
||||||
|
一个由数组第1,2,3个元素组成的分片可以这么生成: s := [3]int{1,2,3} 或者 s := [...]int{1,2,3}[:]甚至更简单的s := []int{1,2,3}。
|
||||||
|
|
||||||
|
s2 := s[:]是用slice组成的slice,拥有相同的元素,但是仍然指向相同的相关数组。
|
||||||
|
|
||||||
|
一个slice s可以这样扩展到它的大小上限:s = s[:cap(s)],如果再扩大的话就会导致运行时错误(参见7.7)。
|
||||||
|
|
||||||
|
对于每一个slice(包括string),以下状态总是成立的:
|
||||||
|
|
||||||
|
s == s[:i] + s[i:] // i是一个整数且: 0 <= i <= len(s)
|
||||||
|
len(s) < cap(s)
|
||||||
|
|
||||||
|
Slice也可以用类似数组的方式初始化: var x = []int{2, 3, 5, 7, 11}。这样就创建了一个长度为5的数组并且创建了一个相关slice。
|
||||||
|
|
||||||
|
slice在内存中的组织方式实际上是一个有3个域的结构体:指向相关数组的指针,slice长度以及slice容量。下图给出了一个长度为2,容量为4的slice。
|
||||||
|
|
||||||
|
y[0] = 3且y[1] = 5。slice y[0:4]由元素3, 5, 7和11组成。 
|
||||||
|
|
||||||
|
示例 7.7 [array_slices.go](exmaples/chapter_7/array_slices.go)
|
||||||
|
|
||||||
|
package main
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var arr1 [6]int
|
||||||
|
var slice1 []int = arr1[2:5] // item at index 5 not included!
|
||||||
|
|
||||||
|
// load the array with integers: 0,1,2,3,4,5
|
||||||
|
for i := 0; i < len(arr1); i++ {
|
||||||
|
arr1[i] = i
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the slice
|
||||||
|
for i := 0; i < len(slice1); i++ {
|
||||||
|
fmt.Printf("Slice at %d is %d\n", i, slice1[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("The length of arr1 is %d\n", len(arr1))
|
||||||
|
fmt.Printf("The length of slice1 is %d\n", len(slice1))
|
||||||
|
fmt.Printf("The capacity of slice1 is %d\n", cap(slice1))
|
||||||
|
|
||||||
|
// grow the slice
|
||||||
|
slice1 = slice1[0:4]
|
||||||
|
for i := 0; i < len(slice1); i++ {
|
||||||
|
fmt.Printf("Slice at %d is %d\n", i, slice1[i])
|
||||||
|
}
|
||||||
|
fmt.Printf("The length of slice1 is %d\n", len(slice1))
|
||||||
|
fmt.Printf("The capacity of slice1 is %d\n", cap(slice1))
|
||||||
|
|
||||||
|
// grow the slice beyond capacity
|
||||||
|
//slice1 = slice1[0:7 ] // panic: runtime error: slice bound out of range
|
||||||
|
}
|
||||||
|
|
||||||
|
输出:
|
||||||
|
Slice at 0 is 2
|
||||||
|
Slice at 1 is 3
|
||||||
|
Slice at 2 is 4
|
||||||
|
The length of arr1 is 6
|
||||||
|
The length of slice1 is 3
|
||||||
|
The capacity of slice1 is 4
|
||||||
|
Slice at 0 is 2
|
||||||
|
Slice at 1 is 3
|
||||||
|
Slice at 2 is 4
|
||||||
|
Slice at 3 is 5
|
||||||
|
The length of slice1 is 4
|
||||||
|
The capacity of slice1 is 4
|
||||||
|
|
||||||
|
如果s2是一个slice,你可以将s2向后移动一位s2 = s2[1:],但是末尾没有移动。slice只能向后移动,s2 = s2[-1:]会导致编译错误。slice不能被重新分片以获取数组的前一个元素。
|
||||||
|
|
||||||
|
`注意`绝对不要用指针指向slice。slice本身已经是一个引用类型,所以它本身就是一个指针!!
|
||||||
|
|
||||||
|
问题7.2: 给定slice b:= []byte{'g', 'o', 'l', 'a', 'n', 'g'},那么b[1:4],b[:2],b[2:]和b[:]分别是什么?
|
||||||
|
|
||||||
|
## 7.2.2 将slice传递给函数
|
||||||
|
如果你有一个函数需要对数组做操作,你可能总是需要把参数声明为slice。当你调用该函数时,把数组分片,创建为一个slice引用并传递给该函数。这里有一个计算数组元素和的方法:
|
||||||
|
|
||||||
|
func sum(a []int) int {
|
||||||
|
s := 0
|
||||||
|
for i := 0; i < len(a); i++ {
|
||||||
|
s += a[i]
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func main {
|
||||||
|
var arr = [5]int{0, 1, 2, 3, 4}
|
||||||
|
sum(arr[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
## 7.2.3 用make()创建一个slice
|
||||||
|
当相关数组还没有定义时,我们可以使用make()方法来创建一个slice同时创建好相关数组: var slice1 []type = make([]type, len)
|
||||||
|
|
||||||
|
也可以简写为 slice1 := make([]type, len),这里len是数组的长度并且也是slice的初始长度。
|
||||||
|
|
||||||
|
所以定义s2 := make([]int, 10),那么cap(s2) == len(s2) == 10
|
||||||
|
|
||||||
|
make接受2个参数:元素的类型以及slice的元素个数。
|
||||||
|
|
||||||
|
如果你想创建一个slice1,它不占用整个数组,而只是占用以len为个数个项,那么只要: slice1 := make([]type, len, cap)
|
||||||
|
|
||||||
|
make的使用方式是: func make([]T, len, cap) 其中cap是可选参数。
|
||||||
|
|
||||||
|
所以下面两种方法可以生成相同的slice:
|
||||||
|
|
||||||
|
make([]int, 50, 100)
|
||||||
|
new([100]int)[0:50]
|
||||||
|
|
||||||
|
下图描述了使用make方法生成的slice的内存结构:
|
||||||
|
|
||||||
|
示例 7.8 [make_slice.go](exmaples/chapter_7/make_slice.go)
|
||||||
|
|
||||||
|
package main
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var slice1 []int = make([]int, 10)
|
||||||
|
// load the array/slice:
|
||||||
|
for i := 0; i < len(slice1); i++ {
|
||||||
|
slice1[i] = 5 * i
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the slice:
|
||||||
|
for i := 0; i < len(slice1); i++ {
|
||||||
|
fmt.Printf("Slice at %d is %d\n", i, slice1[i])
|
||||||
|
}
|
||||||
|
fmt.Printf("\nThe length of slice1 is %d\n", len(slice1))
|
||||||
|
fmt.Printf("The capacity of slice1 is %d\n", cap(slice1))
|
||||||
|
}
|
||||||
|
|
||||||
|
输出结构:
|
||||||
|
Slice at 0 is 0
|
||||||
|
Slice at 1 is 5
|
||||||
|
Slice at 2 is 10
|
||||||
|
Slice at 3 is 15
|
||||||
|
Slice at 4 is 20
|
||||||
|
Slice at 5 is 25
|
||||||
|
Slice at 6 is 30
|
||||||
|
Slice at 7 is 35
|
||||||
|
Slice at 8 is 40
|
||||||
|
Slice at 9 is 45
|
||||||
|
The length of slice1 is 10
|
||||||
|
The capacity of slice1 is 10
|
||||||
|
|
||||||
|
因为字符串是纯粹不可变的字节数组,它们也可以被切分成slice。
|
||||||
|
|
||||||
|
练习 7.4: fobinacci_funcarray.go: 为练习7.3写一个新的版本,主函数调用一个使用序列个数作为参数的函数,该函数返回一个大小为序列个数的Fibonacci slice。
|
||||||
|
|
||||||
|
## 7.2.4 new()和make()的区别
|
||||||
|
看起来二者没有什么区别,都在堆上分配内存,但是它们的行为不同,适用于不同的类型。
|
||||||
|
|
||||||
|
new(T)为每个新的类型T分配一片内存,初始化为0并且返回内存地址,类型*T:这种方法`返回一个指向类型为T,值为0的地址的指针`,它适用于值类型如数组和结构体(参见第十章);它相当于&T{}
|
||||||
|
|
||||||
|
make(T)`返回一个类型为T的初始值`,它只适用于3种内建的引用类型:slice, map和channel(参见第8章,第13章)
|
||||||
|
|
||||||
|
换言之,new方法分配内存,make方法初始化;下图给出了区别:
|
||||||
|
|
||||||
|
在图7.3的第一幅图中:
|
||||||
|
|
||||||
|
var p *[]int = new([]int) // *p == nil; with len and cap 0
|
||||||
|
p := new([]int)
|
||||||
|
|
||||||
|
在第二幅图中, p := make([]int, 0) ,slice已经被初始化,但是指向一个空的数组。
|
||||||
|
|
||||||
|
这两种方式实用性都不高,下面的方法:
|
||||||
|
|
||||||
|
var v []int = make([]int, 10, 50)
|
||||||
|
|
||||||
|
或者
|
||||||
|
|
||||||
|
v := make([]int, 10, 50)
|
||||||
|
|
||||||
|
这样分配一个有50个int值的数组,并且创建了一个长度为10,容量为50的slice v,该slice指向数组的前10个元素。
|
||||||
|
|
||||||
|
问题 7.3:给定s := make([]byte, 5),len(s)和cap(s)分别是多少?s = s[2:4],len(s)和cap(s)又分别是多少?
|
||||||
|
问题 7.4:假设s1 := []byte{'p', 'o', 'e', 'm'}且s2 := d[2:],s2的值是多少?如果我们执行s2[1] == 't',s1和s2现在的值又分配是多少?
|
||||||
|
|
||||||
|
## 7.2.5 多维slice
|
||||||
|
和数组一样,slice通常也是一维的,但是也可以由一维组合成高维。通过分片的分片(或者slice的数组),长度可以任意动态变化,所以Go语言的多维slice可以任意切分。而且,内层的slice必须单独分配(通过make方法)
|
||||||
|
|
||||||
|
## 7.2.6 bytes包
|
||||||
|
bytes的slice十分常见,Go语言有一个bytes包专门用来解决这种类型的操作方法。
|
||||||
|
|
||||||
|
bytes包和字符串包十分类似(参见4.7)。而且它还包含一个十分有用的类型Buffer:
|
||||||
|
|
||||||
|
import "bytes"
|
||||||
|
type Buffer struct {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
这是一个bytes的定长buffer,提供Read和Write方法,因为读写不知道长度的bytes最好使用buffer。
|
||||||
|
|
||||||
|
Buffer可以这样定义: var buffer bytes.Buffer
|
||||||
|
|
||||||
|
或者new出一个指针: var r *bytes.Buffer = new(bytes.Buffer)
|
||||||
|
|
||||||
|
或者通过函数: func NewBuffer(buf []byte) *Buffer,这就用创建了一个Buffer对象并且用buf初始化好了;NewBuffer最好用在从buf读取的时候使用。
|
||||||
|
|
||||||
|
通过buffer串联字符串:类似于Java的StringBuilder类。
|
||||||
|
|
||||||
|
创建一个Buffer,通过buffer.WriteString(s)方法将每个string s追加到后面,最后再通过buffer.String()方法转换为string,下面是代码段:
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
for {
|
||||||
|
if s, ok := getNextString(); ok { //method getNextString() not shown here
|
||||||
|
buffer.WriteString(s)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Print(buffer.String(), "\n")
|
||||||
|
|
||||||
|
这种实现方式比使用`+=`要更节省内存和CPU,尤其是要串联的字符串数目特别多的时候。
|
||||||
|
|
||||||
|
练习:
|
||||||
|
|
||||||
|
练习 7.5: 给定slice sl,将a []byte数组追加到sl后面。写一个函数Append(slice, data []byte) []byte,该函数在sl不能存储更多数据的时候自动扩容。
|
||||||
|
练习 7.6: 把一个缓存buf分片成两个slice:第一个是前n个bytes,后一个是剩余的,用一行代码实现。
|
||||||
|
|
||||||
|
##链接
|
||||||
|
- [目录](directory.md)
|
||||||
|
- 上一节:[声明和初始化](07.1.md)
|
||||||
|
- 下一节:[For range构建方法](07.3.md)
|
94
eBook/07.3.md
Normal file
94
eBook/07.3.md
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#7.3 For range构建方法
|
||||||
|
|
||||||
|
这种构建方法可以应用与数组和slice:
|
||||||
|
for ix, value := range slice1 {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
第一个返回值dx是数组或者slice的索引,第二个是在该索引位置的值;他们都是仅在for循环内部可见的局部变量,所以该值只是该索引项slice值的一个拷贝并且不能被修改。
|
||||||
|
|
||||||
|
示例 7.9 [slices_forrange.go](exmaples/chapter_7/slices_forrange.go)
|
||||||
|
|
||||||
|
package main
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var arr1 [5]int
|
||||||
|
|
||||||
|
for i:=0; i < len(arr1); i++ {
|
||||||
|
arr1[i] = i * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
for i:=0; i < len(arr1); i++ {
|
||||||
|
fmt.Printf("Array at index %d is %d\n", i, arr1[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
示例 7.10 [slices_forrange2.go](exmaples/chapter_7/slices_forrange2.go)
|
||||||
|
|
||||||
|
package main
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
seasons := []string{"Spring", "Summer", "Autumn", "Winter"}
|
||||||
|
for ix, season := range seasons {
|
||||||
|
fmt.Printf("Season %d is: %s\n", ix, season)
|
||||||
|
}
|
||||||
|
|
||||||
|
var season string
|
||||||
|
for _, season = range seasons {
|
||||||
|
fmt.Printf("%s\n", season)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slices_forrange2.go给出了一个关于字符串的例子, `_`可以用于忽略索引。
|
||||||
|
|
||||||
|
如果你只需要索引,你可以忽略第二个变量,例如:
|
||||||
|
|
||||||
|
for ix := range seasons {
|
||||||
|
fmt.Printf("%d", ix)
|
||||||
|
}
|
||||||
|
// Output: 0 1 2 3
|
||||||
|
|
||||||
|
如果你需要修改seasons[ix]的值可以使用这个版本。
|
||||||
|
|
||||||
|
多维slice下的for range方法:
|
||||||
|
|
||||||
|
通过计算行数和矩阵值可以很方便的写出如(参考7.1.3)的for-loops方法来,例如(参考7.5的例子multidim_array.go):
|
||||||
|
|
||||||
|
for row := range screen {
|
||||||
|
for column := range screen[0] {
|
||||||
|
screen[row][column] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
问题 7.5: 假设我们有如下slice: items := [...]int{10, 20, 30, 40, 50}
|
||||||
|
|
||||||
|
a) 如果我们写了如下的for循环,那么执行完for循环后的item的值是多少?如果你不确定的话可以测试一下:)
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
item *= 2
|
||||||
|
}
|
||||||
|
|
||||||
|
b) 如果a)无法正常工作,写一个for循环让值可以double。
|
||||||
|
|
||||||
|
问题 7.6: 通过使用省略号操作符`...`来实现累加方法。
|
||||||
|
|
||||||
|
练习:
|
||||||
|
|
||||||
|
练习 7.7 sum_array.go
|
||||||
|
|
||||||
|
a) 写一个Sum函数,传入参数为一个4位float数组成的数组arrF,返回该数组的所有数字和。
|
||||||
|
|
||||||
|
如果把数组修改为slice的话代码要做怎样的修改?如果用slice形式方法实现不同长度数组的的和呢?
|
||||||
|
|
||||||
|
b) 写一个SumAndAverage方法,返回两个int和float32类型的未命名变量的和与平均值。
|
||||||
|
|
||||||
|
练习 7.8 min_max.go
|
||||||
|
|
||||||
|
写一个minSlice方法,传入一个int的slice并且返回最小值,再写一个maxSlice方法返回最大值。
|
||||||
|
|
||||||
|
##链接
|
||||||
|
- [目录](directory.md)
|
||||||
|
- 上一节:[分片](07.2.md)
|
||||||
|
- 下一节:[分片重组](07.4.md)
|
75
eBook/07.4.md
Normal file
75
eBook/07.4.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#7.4 分片重组
|
||||||
|
我们已经知道slice创建的时候通常比相关数组小,例如
|
||||||
|
|
||||||
|
slice1 := make([]type, start_length, capacity)
|
||||||
|
|
||||||
|
其中start_length作为slice初始长度而capacity作为相关数组的长度。
|
||||||
|
|
||||||
|
这么做的好处是我们的slice在达到容量上限后可以扩容。改变slice长度的过程称之为分片重组`reslicing`,做法如下:slice1 = slice1[0:end],其中end是新的末尾索引(即长度)。
|
||||||
|
|
||||||
|
将slice扩展1位可以这么做: sl = sl[0:len(sl)+1]
|
||||||
|
|
||||||
|
slice可以反复扩展直到占据整个相关数组。
|
||||||
|
|
||||||
|
|
||||||
|
示例 7.11 [reslicing.go](exmaples/chapter_7/reslicing.go)
|
||||||
|
|
||||||
|
package main
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
slice1 := make([]int, 0, 10)
|
||||||
|
// load the slice, cap(slice1) is 10:
|
||||||
|
for i := 0; i < cap(slice1); i++ {
|
||||||
|
slice1 = slice1[0:i+1]
|
||||||
|
slice1[i] = i
|
||||||
|
fmt.Printf("The length of slice is %d\n", len(slice1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the slice:
|
||||||
|
for i := 0; i < len(slice1); i++ {
|
||||||
|
fmt.Printf("Slice at %d is %d\n", i, slice1[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
输出结果:
|
||||||
|
The length of slice is 1
|
||||||
|
The length of slice is 2
|
||||||
|
The length of slice is 3
|
||||||
|
The length of slice is 4
|
||||||
|
The length of slice is 5
|
||||||
|
The length of slice is 6
|
||||||
|
The length of slice is 7
|
||||||
|
The length of slice is 8
|
||||||
|
The length of slice is 9
|
||||||
|
The length of slice is 10
|
||||||
|
Slice at 0 is 0
|
||||||
|
Slice at 1 is 1
|
||||||
|
Slice at 2 is 2
|
||||||
|
Slice at 3 is 3
|
||||||
|
Slice at 4 is 4
|
||||||
|
Slice at 5 is 5
|
||||||
|
Slice at 6 is 6
|
||||||
|
Slice at 7 is 7
|
||||||
|
Slice at 8 is 8
|
||||||
|
Slice at 9 is 9
|
||||||
|
|
||||||
|
另一个例子:
|
||||||
|
|
||||||
|
var ar = [10]int{0,1,2,3,4,5,6,,7,8,9}
|
||||||
|
var a = ar[5:7] // reference to subarray {5,6} - len(a) is 2 and cap(a) is 5
|
||||||
|
|
||||||
|
将a重新分片
|
||||||
|
|
||||||
|
a = a[0:4] // ref of subarray {5,6,7,8} - len(a) is now 4 but cap(a) is still 5
|
||||||
|
|
||||||
|
问题 7.7:
|
||||||
|
|
||||||
|
1) 如果a是一个slice,那么s[n:n]的长度是多少?
|
||||||
|
|
||||||
|
2) s[n:n+1]的长度又是多少?
|
||||||
|
|
||||||
|
##链接
|
||||||
|
- [目录](directory.md)
|
||||||
|
- 上一节:[For range构建方法](07.3.md)
|
||||||
|
- 下一节:[拷贝与追加slice](07.5.md)
|
55
eBook/07.5.md
Normal file
55
eBook/07.5.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#7.5 拷贝与追加slice
|
||||||
|
如果想增加slice的容量,我们必须创建一个新的更大的slice并把原分片的内容都拷贝过来。下面的代码描述了从拷贝slice的copy方法和向slice追加新元素的append方法。
|
||||||
|
|
||||||
|
示例 7.12 [copy_append_slice.go](exmaples/chapter_7/copy_append_slice.go)
|
||||||
|
|
||||||
|
package main
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sl_from := []int{1, 2, 3}
|
||||||
|
sl_to := make([]int, 10)
|
||||||
|
|
||||||
|
n := copy(sl_to, sl_from)
|
||||||
|
fmt.Println(sl_to)
|
||||||
|
fmt.Printf("Copied %d elements\n", n) // n == 3
|
||||||
|
|
||||||
|
sl3 := []int{1, 2, 3}
|
||||||
|
sl3 = append(sl3, 4, 5, 6)
|
||||||
|
fmt.Println(sl3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func append(s[]T, x ...T) []T 其中append方法将0个或多个具有相同类型s的元素追加到slice后面并且返回新的slice;追加的元素必须和原slice的元素同类型。如果s的容量不足以存储新增元素,append会分配新的slice来保证已有slice元素和新增元素的存储。因此,返回的slice可能已经指向一个不同的相关数组了。append方法总是返回成功,除非系统内存耗尽了。
|
||||||
|
|
||||||
|
如果你想将slice y追加到slice x后面,只要将第二个参数扩展成一个列表即可: x = append(x, y...)
|
||||||
|
|
||||||
|
**注意**: append在大多数情况下很好用,但是如果你想完全掌控整个追加过程,你可以实现一个这样的AppendByte方法:
|
||||||
|
|
||||||
|
func AppendByte(slice []byte, data ...byte[]) []byte {
|
||||||
|
m := len(slice)
|
||||||
|
n := m + len(data)
|
||||||
|
if n > cap(slice) { // if necessary, reallocate
|
||||||
|
// allocate doublke what's needed, for future growth.
|
||||||
|
newSlice := make([]byte, (n+1)*2)
|
||||||
|
copy(newSlice, slice)
|
||||||
|
slice = newSlice
|
||||||
|
}
|
||||||
|
slice = slice[0:n]
|
||||||
|
copy(slice[m:n], data)
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
|
||||||
|
func copy(dst, src []T) int copy方法将类型为T的slice从源地址src拷贝到目标地址dst,覆盖dst的相关元素,并且返回拷贝的元素个数。源地址和目标地址可能会有重叠。拷贝个数是src和dst的长度最小值。如果src是字符串那么元素类型就是byte。如果你还想继续使用src,在拷贝技术后执行src =dst。
|
||||||
|
|
||||||
|
练习 7.9: magnify_slice.go: 给定slice s[]int和一个int类型的因子,扩展s使其长度为len(s) * factor。
|
||||||
|
|
||||||
|
练习 7.10:filter_slice.go: 用顺序函数过滤容器:s是前10个整形的slice。构造一个函数Filter,第一个参数是s,第二个参数是一个fn func(int) bool,返回满足函数fn的元素slice。通过fn测试方法测试当整型值是偶数时的情况。
|
||||||
|
|
||||||
|
练习 7.11:insert_slice.go:写一个函数InsertStringSlice将slice插入到另一个slice的指定位置。
|
||||||
|
|
||||||
|
练习 7.12:remove_slice.go:写一个函数RemoveStringSlice将从start到end索引的元素从slice中移除。
|
||||||
|
|
||||||
|
##链接
|
||||||
|
- [目录](directory.md)
|
||||||
|
- 上一节:[分片重组](07.4.md)
|
||||||
|
- 下一节:[字符串,数组和slice应用](07.6.md)
|
14
eBook/examples/chapter_7/slices_forrange2.go
Normal file
14
eBook/examples/chapter_7/slices_forrange2.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package main
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
seasons := []string{"Spring", "Summer", "Autumn", "Winter"}
|
||||||
|
for ix, season := range seasons {
|
||||||
|
fmt.Printf("Season %d is: %s\n", ix, season)
|
||||||
|
}
|
||||||
|
|
||||||
|
var season string
|
||||||
|
for _, season = range seasons {
|
||||||
|
fmt.Printf("%s\n", season)
|
||||||
|
}
|
||||||
|
}
|
BIN
eBook/images/7.2_fig7.2.1.png
Normal file
BIN
eBook/images/7.2_fig7.2.1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 70 KiB |
BIN
eBook/images/7.2_fig7.2.png
Normal file
BIN
eBook/images/7.2_fig7.2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 122 KiB |
BIN
eBook/images/7.3_fig7.3.png
Normal file
BIN
eBook/images/7.3_fig7.3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 83 KiB |
Reference in New Issue
Block a user