mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-11 22:53:43 +08:00
07.1
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
## 翻译进度
|
## 翻译进度
|
||||||
|
|
||||||
7.0 [数组与切片](eBook/07.0.md)
|
7.1 [声明和初始化](eBook/07.1.md)
|
||||||
|
|
||||||
## 支持本书
|
## 支持本书
|
||||||
|
|
||||||
|
@@ -3,36 +3,36 @@
|
|||||||
157
|
157
|
||||||
|
|
||||||
##7.1.1 概念
|
##7.1.1 概念
|
||||||
数组是具有相同`唯一类型`的一组已编号且长度固定的数据项序列(这是一种同构的数据结构);这种类型可以是任意的原始类型例如整形、字符串或者自定义类型。数组长度必须是一个常量表达式,并且必须是一个非负整数。数组长度也是数组类型的一部分,所以[5]int和[10]int是属于不同类型的。数组的编译时值初始化是按照数组顺序完成的(如下)。
|
数组是具有相同 **唯一类型** 的一组已编号且长度固定的数据项序列(这是一种同构的数据结构);这种类型可以是任意的原始类型例如整形、字符串或者自定义类型。数组长度必须是一个常量表达式,并且必须是一个非负整数。数组长度也是数组类型的一部分,所以[5]int和[10]int是属于不同类型的。数组的编译时值初始化是按照数组顺序完成的(如下)。
|
||||||
|
|
||||||
**注意事项**
|
**注意事项**
|
||||||
如果我们想让数组元素类型为任意类型的话可以使用空接口作为类型(参考[第11章](11.9.md))。当使用值时我们必须先做一个类型判断(参考[第11章](11.3.md))。
|
如果我们想让数组元素类型为任意类型的话可以使用空接口作为类型(参考 [第 11 章](11.9.md))。当使用值时我们必须先做一个类型判断(参考 [第 11 章](11.3.md))。
|
||||||
|
|
||||||
数组元素可以通过`索引`(位置)来读取(或者修改),索引从0开始,第一个元素索引为0,第二个索引为1,以此类推。(数组以0开始在所有类C语言中是相似的)。元素的数目,也称为`length`或者数组大小必须是固定的并且在声明该数组时就给出(编译时需要知道数组长度以便分配内存);数组长度最大为2Gb。
|
数组元素可以通过 **索引**(位置)来读取(或者修改),索引从0开始,第一个元素索引为 0,第二个索引为 1,以此类推。(数组以 0 开始在所有类C语言中是相似的)。元素的数目,也称为长度或者数组大小必须是固定的并且在声明该数组时就给出(编译时需要知道数组长度以便分配内存);数组长度最大为 2Gb。
|
||||||
|
|
||||||
声明的格式是: var identifier [len]type
|
声明的格式是: `var identifier [len]type`
|
||||||
|
|
||||||
例如: var arr1 [5]int
|
例如: `var arr1 [5]int`
|
||||||
|
|
||||||
在内存中的结构是:
|
在内存中的结构是:
|
||||||
|
|
||||||
每个元素是一个整形值,当声明数组时所有的元素都会被自动初始化为默认值0.
|
每个元素是一个整形值,当声明数组时所有的元素都会被自动初始化为默认值0.
|
||||||
|
|
||||||
arr1的长度是5,索引范围从0到len(arr1)-1
|
arr1 的长度是 5,索引范围从 0 到 len(arr1)-1
|
||||||
|
|
||||||
第一个元素是arr1[0],第3个元素是arr1[2];总体来说索引i代表的元素是arr1[i],最后一个元素是arr1[len(arr1)-1]。
|
第一个元素是 arr1[0],第三个元素是 arr1[2];总体来说索引 i 代表的元素是 arr1[i],最后一个元素是 arr1[len(arr1)-1]。
|
||||||
|
|
||||||
对索引项为i的数组元素赋值可以这么操作:arr[i] = value,所以数组是`可变的`。
|
对索引项为 i 的数组元素赋值可以这么操作:arr[i] = value,所以数组是 **可变的**。
|
||||||
|
|
||||||
只有有效的索引可以被使用,当使用等于或者大于len(arr1)的索引时:如果编译器可以检测到,会给出索引超限的提示信息;如果检测不到的话编译会通过而运行时会panic:(参考[第13章](13.0.md))
|
只有有效的索引可以被使用,当使用等于或者大于 len(arr1) 的索引时:如果编译器可以检测到,会给出索引超限的提示信息;如果检测不到的话编译会通过而运行时会 panic:(参考 [第 13 章](13.0.md))
|
||||||
|
|
||||||
runtime error: index out of range
|
runtime error: index out of range
|
||||||
|
|
||||||
由于索引的存在,遍历数组的方法自然就是使用for-construct:
|
由于索引的存在,遍历数组的方法自然就是使用 for-construct:
|
||||||
|
|
||||||
- 通过for初始化数组项
|
- 通过 for 初始化数组项
|
||||||
- 通过for打印数组元素
|
- 通过 for 打印数组元素
|
||||||
- 通过for依次处理元素
|
- 通过 for 依次处理元素
|
||||||
|
|
||||||
示例 7.1 [for_arrays.go](exmaples/chapter_7/for_arrays.go)
|
示例 7.1 [for_arrays.go](exmaples/chapter_7/for_arrays.go)
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ IDIOM:
|
|||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
在这里i也是数组的索引。当然这两种for-construct方式对于分片(slices)(参考[第7章](07.2.md))来说也同样适用。
|
在这里i也是数组的索引。当然这两种 for-construct 方式对于切片(slices)(参考 [第 7 章](07.2.md))来说也同样适用。
|
||||||
|
|
||||||
**问题 7.1** 下面代码段的输出是什么?
|
**问题 7.1** 下面代码段的输出是什么?
|
||||||
|
|
||||||
@@ -84,20 +84,20 @@ IDIOM:
|
|||||||
fmt.Println("Array item", i, "is", a[i])
|
fmt.Println("Array item", i, "is", a[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
Go语言中的数组是一种`值类型`(不像C/C++中是指向首元素的指针),所以可以通过`new()`来创建: var arr1 = new([5]int)
|
Go语言中的数组是一种 **值类型**(不像C/C++中是指向首元素的指针),所以可以通过 `new()` 来创建: `var arr1 = new([5]int)`
|
||||||
|
|
||||||
那么这种方式和var arr2 [5]int的区别是什么呢?arr1的类型是*[5]int,而arr2的类型是[5]int。
|
那么这种方式和 `var arr2 [5]int` 的区别是什么呢?arr1 的类型是 `*[5]int`,而 arr2的类型是 `[5]int`。
|
||||||
|
|
||||||
这样的结果就是当把一个数组赋值给另一个时,需要在做一次数组内存的拷贝操作。例如:
|
这样的结果就是当把一个数组赋值给另一个时,需要在做一次数组内存的拷贝操作。例如:
|
||||||
|
|
||||||
arr := arr1
|
arr := arr1
|
||||||
arr2[2] = 100
|
arr2[2] = 100
|
||||||
|
|
||||||
这样两个数组就有了不同的值,在赋值后修改arr2不会对arr1生效。
|
这样两个数组就有了不同的值,在赋值后修改 arr2 不会对 arr1 生效。
|
||||||
|
|
||||||
所以在函数中数组作为参数传入时,如func1(arr1),会产生一次数组拷贝,func1方法不会修改原始的数组arr1。
|
所以在函数中数组作为参数传入时,如 func1(arr1),会产生一次数组拷贝,func1 方法不会修改原始的数组 arr1。
|
||||||
|
|
||||||
如果你想修改原数组,那么arr1必须通过&操作符以引用方式传过来,例如func1(&arr1),下面是一个例子
|
如果你想修改原数组,那么 arr1 必须通过&操作符以引用方式传过来,例如 func1(&arr1),下面是一个例子
|
||||||
|
|
||||||
Example 7.2 [pointer_array.go](examples/chapter_7/pointer_array.go):
|
Example 7.2 [pointer_array.go](examples/chapter_7/pointer_array.go):
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ Example 7.2 [pointer_array.go](examples/chapter_7/pointer_array.go):
|
|||||||
[0 0 0]
|
[0 0 0]
|
||||||
&[0 0 0]
|
&[0 0 0]
|
||||||
|
|
||||||
另一种方法就是生成数组分片slice并将其传递给函数(参见传递数组参数给函数7.1.4节)
|
另一种方法就是生成数组切片并将其传递给函数(参见传递数组参数给函数7.1.4节)
|
||||||
|
|
||||||
**练习**
|
**练习**
|
||||||
|
|
||||||
@@ -127,8 +127,9 @@ Example 7.2 [pointer_array.go](examples/chapter_7/pointer_array.go):
|
|||||||
|
|
||||||
练习7.3:fibonacci_array.go: 在6.6节我们看到了一个递归计算Fibonacci数值的方法。但是通过数组我们可以更快的计算出Fibonacci数。完成该方法并打印出前50个Fibonacci数字。
|
练习7.3:fibonacci_array.go: 在6.6节我们看到了一个递归计算Fibonacci数值的方法。但是通过数组我们可以更快的计算出Fibonacci数。完成该方法并打印出前50个Fibonacci数字。
|
||||||
|
|
||||||
##7.1.2 数组常量
|
## 7.1.2 数组常量
|
||||||
如果数组值已经提前知道了,那么可以通过`数组常量`的方法来初始化数组,而不用依次使用[]=方法。(所有的组成元素都有相同的常量语法)
|
|
||||||
|
如果数组值已经提前知道了,那么可以通过 **数组常量** 的方法来初始化数组,而不用依次使用 `[]=` 方法(所有的组成元素都有相同的常量语法)。
|
||||||
|
|
||||||
Example 7.3 [array_literals.go](examples/chapter_7/array_literals.go)
|
Example 7.3 [array_literals.go](examples/chapter_7/array_literals.go)
|
||||||
|
|
||||||
@@ -147,19 +148,19 @@ Example 7.3 [array_literals.go](examples/chapter_7/array_literals.go)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
第一种变化: var arrAge = [5]int{18, 20, 15, 22, 16}
|
第一种变化: `var arrAge = [5]int{18, 20, 15, 22, 16}`
|
||||||
|
|
||||||
注意[5]int可以从左边起开始忽略:[10]int {1, 2, 3} :这是一个有10个元素的数组,除了前三个元素外其他元素都为0。
|
注意 `[5]int` 可以从左边起开始忽略:`[10]int {1, 2, 3}` :这是一个有 10 个元素的数组,除了前三个元素外其他元素都为 0。
|
||||||
|
|
||||||
第二种变化: var arrLazy = [...]int{5, 6, 7, 8, 22}
|
第二种变化: `var arrLazy = [...]int{5, 6, 7, 8, 22}`
|
||||||
|
|
||||||
`...`可同样可以忽略,从技术上说它们其实变化成了slice。
|
`...` 可同样可以忽略,从技术上说它们其实变化成了切片。
|
||||||
|
|
||||||
第三种变化:key: value syntax
|
第三种变化:`key: value syntax`
|
||||||
|
|
||||||
var arrKeyValue = [5]string{3: "Chris", 4:"Ron"}
|
var arrKeyValue = [5]string{3: "Chris", 4:"Ron"}
|
||||||
|
|
||||||
只有索引3和4被赋予实际的值,其他元素都被设置为空的字符串,所以输出结果为:
|
只有索引 3 和 4 被赋予实际的值,其他元素都被设置为空的字符串,所以输出结果为:
|
||||||
|
|
||||||
Person at 0 is
|
Person at 0 is
|
||||||
Person at 1 is
|
Person at 1 is
|
||||||
@@ -167,7 +168,7 @@ Example 7.3 [array_literals.go](examples/chapter_7/array_literals.go)
|
|||||||
Person at 3 is Chris
|
Person at 3 is Chris
|
||||||
Person at 4 is Ron
|
Person at 4 is Ron
|
||||||
|
|
||||||
在这里数组长度同样可以写成`...`或者直接忽略。
|
在这里数组长度同样可以写成 `...` 或者直接忽略。
|
||||||
|
|
||||||
你可以取任意数组常量的地址来作为指向新实例的指针。
|
你可以取任意数组常量的地址来作为指向新实例的指针。
|
||||||
|
|
||||||
@@ -196,9 +197,10 @@ Example 7.4 [pointer_array2.go](examples/chapter_7/pointer_array2.go)
|
|||||||
var vec Vector3D
|
var vec Vector3D
|
||||||
|
|
||||||
## 7.1.3 多维数组
|
## 7.1.3 多维数组
|
||||||
数组通常是1维的,但是可以用来组装成多维数组,例如:[3][5]int,[2][2][2]float64
|
|
||||||
|
|
||||||
内部数组总是长度相同的。Go语言的多维数组是矩形式的(唯一的例外是分片slice的数组,参见7.2.5)
|
数组通常是1维的,但是可以用来组装成多维数组,例如:`[3][5]int`,`[2][2][2]float64`。
|
||||||
|
|
||||||
|
内部数组总是长度相同的。Go 语言的多维数组是矩形式的(唯一的例外是切片的数组,参见第 7.2.5 节)。
|
||||||
|
|
||||||
Example 7.5 [multidim_array.go](examples/chapter_7/multidim_array.go)
|
Example 7.5 [multidim_array.go](examples/chapter_7/multidim_array.go)
|
||||||
|
|
||||||
@@ -220,9 +222,11 @@ Example 7.5 [multidim_array.go](examples/chapter_7/multidim_array.go)
|
|||||||
}
|
}
|
||||||
|
|
||||||
## 7.1.4 将数组传递给函数
|
## 7.1.4 将数组传递给函数
|
||||||
|
|
||||||
把第一个大数组传递给函数会消耗很多内存。有两种方法可以避免这种现象:
|
把第一个大数组传递给函数会消耗很多内存。有两种方法可以避免这种现象:
|
||||||
|
|
||||||
- 传递数组的指针
|
- 传递数组的指针
|
||||||
- 使用数组的分片slice
|
- 使用数组的切片
|
||||||
|
|
||||||
接下来的例子阐明了第一种方法:
|
接下来的例子阐明了第一种方法:
|
||||||
|
|
||||||
@@ -248,9 +252,10 @@ Example 7.6 [array_sum.go](examples/chapter_7/array_sum.go)
|
|||||||
输出结果:
|
输出结果:
|
||||||
The sum of the array is: 24.600000
|
The sum of the array is: 24.600000
|
||||||
|
|
||||||
但这在Go中并不常用,通常使用分片slice。(参考[第7章](07.2.md))
|
但这在 Go 中并不常用,通常使用切片。(参考 [第 7 章](07.2.md))
|
||||||
|
|
||||||
|
## 链接
|
||||||
|
|
||||||
##链接
|
|
||||||
- [目录](directory.md)
|
- [目录](directory.md)
|
||||||
- 上一节:[数组与分片](07.0.md)
|
- 上一节:[数组与切片](07.0.md)
|
||||||
- 下一节:[分片slices](07.2.md)
|
- 下一节:[切片](07.2.md)
|
@@ -1,4 +1,7 @@
|
|||||||
#7.2 分片
|
# 7.2 切片
|
||||||
|
|
||||||
|
164
|
||||||
|
|
||||||
## 7.2.1 概念
|
## 7.2.1 概念
|
||||||
slice是对数组一个连续片段的引用(该数组我们称之为相关数组,通常是匿名的),所以slice是一个引用类型(因此更类似于C/C++中的数组类型,或者Python中的list类型)。这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。需要注意的是,终止索引标识的项不包括在slice内。Slice提供了一个相关数组的动态窗口。
|
slice是对数组一个连续片段的引用(该数组我们称之为相关数组,通常是匿名的),所以slice是一个引用类型(因此更类似于C/C++中的数组类型,或者Python中的list类型)。这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。需要注意的是,终止索引标识的项不包括在slice内。Slice提供了一个相关数组的动态窗口。
|
||||||
|
|
||||||
|
@@ -60,6 +60,7 @@
|
|||||||
- 6.12 [通过内存缓存来提升性能](06.12.md)
|
- 6.12 [通过内存缓存来提升性能](06.12.md)
|
||||||
- 第7章:[数组与切片](07.0.md)
|
- 第7章:[数组与切片](07.0.md)
|
||||||
- 7.1 [声明和初始化](07.1.md)
|
- 7.1 [声明和初始化](07.1.md)
|
||||||
|
- 7.2 [切片](07.2.md)
|
||||||
- 第8章:Maps
|
- 第8章:Maps
|
||||||
- 第9章:包(package)
|
- 第9章:包(package)
|
||||||
- 第10章:结构(struct)与方法(method)
|
- 第10章:结构(struct)与方法(method)
|
||||||
|
Reference in New Issue
Block a user