mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-11-13 09:16:10 +08:00
修改部分描述,添加必要的标点符号,补充代码超链接 (#804)
This commit is contained in:
@@ -8,11 +8,11 @@
|
||||
|
||||
给定项的切片索引可能比相关数组的相同元素的索引小。和数组不同的是,切片的长度可以在运行时修改,最小为 0 最大为相关数组的长度:切片是一个 **长度可变的数组**。
|
||||
|
||||
切片提供了计算容量的函数 `cap()` 可以测量切片最长可以达到多少:它等于切片的长度 + 数组除切片之外的长度。如果 s 是一个切片,`cap(s)` 就是从 `s[0]` 到数组末尾的数组长度。切片的长度永远不会超过它的容量,所以对于 切片 s 来说该不等式永远成立:`0 <= len(s) <= cap(s)`。
|
||||
切片提供了计算容量的函数 `cap()` 可以测量切片最长可以达到多少:它等于切片的长度 + 数组除切片之外的长度。如果 s 是一个切片,`cap(s)` 就是从 `s[0]` 到数组末尾的数组长度。切片的长度永远不会超过它的容量,所以对于切片 s 来说该不等式永远成立:`0 <= len(s) <= cap(s)`。
|
||||
|
||||
多个切片如果表示同一个数组的片段,它们可以共享数据;因此一个切片和相关数组的其他切片是共享存储的,相反,不同的数组总是代表不同的存储。数组实际上是切片的构建块。
|
||||
|
||||
**优点** 因为切片是引用,所以它们不需要使用额外的内存并且比使用数组更有效率,所以在 Go 代码中 切片比数组更常用。
|
||||
**优点** 因为切片是引用,所以它们不需要使用额外的内存并且比使用数组更有效率,所以在 Go 代码中切片比数组更常用。
|
||||
|
||||
声明切片的格式是: `var identifier []type`(不需要说明长度)。
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
切片的初始化格式是:`var slice1 []type = arr1[start:end]`。
|
||||
|
||||
这表示 slice1 是由数组 arr1 从 start 索引到 `end-1` 索引之间的元素构成的子集(切分数组,start:end 被称为 slice 表达式)。所以 `slice1[0]` 就等于 `arr1[start]`。这可以在 arr1 被填充前就定义好。
|
||||
这表示 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`。
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
如果你想去掉 slice1 的最后一个元素,只要 `slice1 = slice1[:len(slice1)-1]`。
|
||||
|
||||
一个由数字 1、2、3 组成的切片可以这么生成:`s := [3]int{1,2,3}[:]`(注: 应先用`s := [3]int{1, 2, 3}`生成数组, 再使用`s[:]`转成切片) 甚至更简单的 `s := []int{1,2,3}`。
|
||||
一个由数字 1、2、3 组成的切片可以这么生成:`s := [3]int{1,2,3}[:]`(注:应先用`s := [3]int{1, 2, 3}`生成数组, 再使用`s[:]`转成切片) 甚至更简单的 `s := []int{1,2,3}`。
|
||||
|
||||
`s2 := s[:]` 是用切片组成的切片,拥有相同的元素,但是仍然指向相同的相关数组。
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
切片也可以用类似数组的方式初始化:`var x = []int{2, 3, 5, 7, 11}`。这样就创建了一个长度为 5 的数组并且创建了一个相关切片。
|
||||
|
||||
切片在内存中的组织方式实际上是一个有 3 个域的结构体:指向相关数组的指针,切片长度以及切片容量。下图给出了一个长度为 2,容量为 4 的切片y。
|
||||
切片在内存中的组织方式实际上是一个有 3 个域的结构体:指向相关数组的指针,切片长度以及切片容量。下图给出了一个长度为 2,容量为 4 的切片 y。
|
||||
|
||||
- `y[0] = 3` 且 `y[1] = 5`。
|
||||
- 切片 `y[0:4]` 由 元素 3,5,7 和 11 组成。
|
||||
@@ -104,13 +104,13 @@ func main() {
|
||||
|
||||
如果 s2 是一个 slice,你可以将 s2 向后移动一位 `s2 = s2[1:]`,但是末尾没有移动。切片只能向后移动,`s2 = s2[-1:]` 会导致编译错误。切片不能被重新分片以获取数组的前一个元素。
|
||||
|
||||
**注意** 绝对不要用指针指向 slice。切片本身已经是一个引用类型,所以它本身就是一个指针!!
|
||||
**注意** 绝对不要用指针指向 slice。切片本身已经是一个引用类型,所以它本身就是一个指针!!
|
||||
|
||||
问题 7.2: 给定切片 `b:= []byte{'g', 'o', 'l', 'a', 'n', 'g'}`,那么 `b[1:4]`、`b[:2]`、`b[2:]` 和 `b[:]` 分别是什么?
|
||||
|
||||
## 7.2.2 将切片传递给函数
|
||||
|
||||
如果你有一个函数需要对数组做操作,你可能总是需要把参数声明为切片。当你调用该函数时,把数组分片,创建为一个 切片引用并传递给该函数。这里有一个计算数组元素和的方法:
|
||||
如果你有一个函数需要对数组做操作,你可能总是需要把参数声明为切片。当你调用该函数时,把数组分片,创建为一个切片引用并传递给该函数。这里有一个计算数组元素和的方法:
|
||||
|
||||
```go
|
||||
func sum(a []int) int {
|
||||
@@ -129,7 +129,7 @@ func main() {
|
||||
|
||||
## 7.2.3 用 make() 创建一个切片
|
||||
|
||||
当相关数组还没有定义时,我们可以使用 make() 函数来创建一个切片 同时创建好相关数组:`var slice1 []type = make([]type, len)`。
|
||||
当相关数组还没有定义时,我们可以使用 make() 函数来创建一个切片,同时创建好相关数组:`var slice1 []type = make([]type, len)`。
|
||||
|
||||
也可以简写为 `slice1 := make([]type, len)`,这里 `len` 是数组的长度并且也是 `slice` 的初始长度。
|
||||
|
||||
@@ -188,7 +188,7 @@ func main() {
|
||||
The length of slice1 is 10
|
||||
The capacity of slice1 is 10
|
||||
|
||||
因为字符串是纯粹不可变的字节数组,它们也可以被切分成 切片。
|
||||
因为字符串是纯粹不可变的字节数组,它们也可以被切分成切片。
|
||||
|
||||
练习 7.4: fobinacci_funcarray.go: 为练习 7.3 写一个新的版本,主函数调用一个使用序列个数作为参数的函数,该函数返回一个大小为序列个数的 Fibonacci 切片。
|
||||
|
||||
@@ -196,8 +196,8 @@ func main() {
|
||||
|
||||
看起来二者没有什么区别,都在堆上分配内存,但是它们的行为不同,适用于不同的类型。
|
||||
|
||||
- new(T) 为每个新的类型T分配一片内存,初始化为 0 并且返回类型为\*T的内存地址:这种方法 **返回一个指向类型为 T,值为 0 的地址的指针**,它适用于值类型如数组和结构体(参见第 10 章);它相当于 `&T{}`。
|
||||
- make(T) **返回一个类型为 T 的初始值**,它只适用于3种内建的引用类型:切片、map 和 channel(参见第 8 章,第 13 章)。
|
||||
- new(T) 为每个新的类型 T 分配一片内存,初始化为 0 并且返回类型为 \*T 的内存地址:这种方法 **返回一个指向类型为 T,值为 0 的地址的指针**,它适用于值类型如数组和结构体(参见第 10 章);它相当于 `&T{}`。
|
||||
- make(T) **返回一个类型为 T 的初始值**,它只适用于 3 种内建的引用类型:切片、map 和 channel(参见第 8 章,第 13 章)。
|
||||
|
||||
换言之,new 函数分配内存,make 函数初始化;下图给出了区别:
|
||||
|
||||
@@ -224,26 +224,26 @@ var v []int = make([]int, 10, 50)
|
||||
v := make([]int, 10, 50)
|
||||
```
|
||||
|
||||
这样分配一个有 50 个 int 值的数组,并且创建了一个长度为 10,容量为 50 的 切片 v,该 切片 指向数组的前 10 个元素。
|
||||
这样分配一个有 50 个 int 值的数组,并且创建了一个长度为 10,容量为 50 的 切片 v,该切片指向数组的前 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 := s1[2:]`,s2 的值是多少?如果我们执行 `s2[1] = 't'`,s1 和 s2 现在的值又分别是多少?
|
||||
|
||||
*译者注:如何理解new、make、slice、map、channel的关系*
|
||||
*译者注:如何理解 new、make、slice、map、channel 的关系*
|
||||
|
||||
*1.slice、map以及channel都是golang内建的一种引用类型,三者在内存中存在多个组成部分,
|
||||
需要对内存组成部分初始化后才能使用,而make就是对三者进行初始化的一种操作方式*
|
||||
*1.slice、map 以及 channel 都是 golang 内建的一种引用类型,三者在内存中存在多个组成部分,
|
||||
需要对内存组成部分初始化后才能使用,而 make 就是对三者进行初始化的一种操作方式*
|
||||
|
||||
*2. new 获取的是存储指定变量内存地址的一个变量,对于变量内部结构并不会执行相应的初始化操作,
|
||||
所以slice、map、channel需要make进行初始化并获取对应的内存地址,而非new简单的获取内存地址*
|
||||
所以 slice、map、channel 需要 make 进行初始化并获取对应的内存地址,而非 new 简单的获取内存地址*
|
||||
|
||||
## 7.2.5 多维 切片
|
||||
## 7.2.5 多维切片
|
||||
|
||||
和数组一样,切片通常也是一维的,但是也可以由一维组合成高维。通过分片的分片(或者切片的数组),长度可以任意动态变化,所以 Go 语言的多维切片可以任意切分。而且,内层的切片必须单独分配(通过 make 函数)。
|
||||
|
||||
## 7.2.6 bytes 包
|
||||
|
||||
类型 `[]byte` 的切片十分常见,Go 语言有一个 bytes 包专门用来解决这种类型的操作方法。
|
||||
类型 `[]byte` 的切片十分常见,Go 语言有一个 bytes 包专门用来提供这种类型的操作方法。
|
||||
|
||||
bytes 包和字符串包十分类似(参见第 4.7 节)。而且它还包含一个十分有用的类型 Buffer:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user