Skip to content

Commit

Permalink
7-8 章修改 (#842)
Browse files Browse the repository at this point in the history
Co-authored-by: Joe Chen <[email protected]>
  • Loading branch information
loftea and unknwon authored May 10, 2022
1 parent c42d8a3 commit 30ca13a
Show file tree
Hide file tree
Showing 14 changed files with 195 additions and 180 deletions.
4 changes: 2 additions & 2 deletions eBook/07.0.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# 7.0 数组与切片

这章我们开始剖析 **集合**,它是可以包含大量条目item的数据结构,例如数组、切片和 map。从这看到 Go 明显受到 Python 的影响。
这章我们开始剖析 **集合**,它是可以包含大量条目 (item) 的数据结构,例如数组、切片和 `map`。从这看到 Go 明显受到 Python 的影响。

`[]` 符号标识的数组类型几乎在所有的编程语言中都是一个基本主力。Go 语言中的数组也是类似的,只是有一些特点。Go 没有 C 那么灵活,但是拥有切片slice类型。这是一种建立在 Go 语言数组类型之上的抽象,要想理解切片我们必须先理解数组。数组有特定的用处,但是却有一些呆板,所以在 Go 语言的代码里并不是特别常见。相对的,切片确实随处可见的。它们构建在数组之上并且提供更强大的能力和便捷。
`[]` 符号标识的数组类型几乎在所有的编程语言中都是一个基本主力。Go 语言中的数组也是类似的,只是有一些特点。Go 没有 C 那么灵活,但是拥有切片 (slice) 类型。这是一种建立在 Go 语言数组类型之上的抽象,要想理解切片我们必须先理解数组。数组有特定的用处,但是却有一些呆板,所以在 Go 语言的代码里并不是特别常见。相对的,切片确实随处可见的。它们构建在数组之上并且提供更强大的能力和便捷。

## 链接

Expand Down
60 changes: 34 additions & 26 deletions eBook/07.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

**注意事项** 如果我们想让数组元素类型为任意类型的话可以使用空接口作为类型(参考 [第 11 章](11.9.md))。当使用值时我们必须先做一个类型判断(参考 [第 11 章](11.3.md))。

数组元素可以通过 **索引**(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1,以此类推(数组以 0 开始在所有类 C 语言中是相似的)。元素的数目(也称为长度或者数组大小)必须是固定的并且在声明该数组时就给出(编译时需要知道数组长度以便分配内存);数组长度最大为 2GB。
数组元素可以通过 **索引**(位置)来读取(或者修改),索引从 `0` 开始,第一个元素索引为 `0`,第二个索引为 `1`,以此类推(数组以 0 开始在所有类 C 语言中是相似的)。元素的数目(也称为长度或者数组大小)必须是固定的并且在声明该数组时就给出(编译时需要知道数组长度以便分配内存);数组长度最大为 2GB。

声明的格式是:

Expand All @@ -23,21 +23,21 @@ var arr1 [5]int

每个元素是一个整型值,当声明数组时所有的元素都会被自动初始化为默认值 0。

arr1 的长度是 5,索引范围从 0`len(arr1)-1`
`arr1` 的长度是 5,索引范围从 `0``len(arr1)-1`

第一个元素是 `arr1[0]`,第三个元素是 `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

由于索引的存在,遍历数组的方法自然就是使用 for 结构:
由于索引的存在,遍历数组的方法自然就是使用 `for` 结构:

- 通过 for 初始化数组项
- 通过 for 打印数组元素
- 通过 for 依次处理元素
- 通过 `for` 初始化数组项
- 通过 `for` 打印数组元素
- 通过 `for` 依次处理元素

示例 7.1 [for_arrays.go](examples/chapter_7/for_arrays.go)

Expand Down Expand Up @@ -66,7 +66,7 @@ func main() {
Array at index 3 is 6
Array at index 4 is 8

for 循环中的条件非常重要:`i < len(arr1)`,如果写成 `i <= len(arr1)` 的话会产生越界错误。
`for` 循环中的条件非常重要:`i < len(arr1)`,如果写成 `i <= len(arr1)` 的话会产生越界错误。

IDIOM:

Expand All @@ -86,7 +86,7 @@ for i,_:= range arr1 {
}
```

在这里i也是数组的索引。当然这两种 for 结构对于切片(slices)(参考 [第 7 章](07.2.md))来说也同样适用。
在这里 `i` 也是数组的索引。当然这两种 `for` 结构对于切片(`slices`)(参考 [第 7 章](07.2.md))来说也同样适用。

**问题 7.1** 下面代码段的输出是什么?

Expand All @@ -99,7 +99,7 @@ for i := range a {

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`

这样的结果就是当把一个数组赋值给另一个时,需要再做一次数组内存的拷贝操作。例如:

Expand All @@ -108,11 +108,11 @@ arr2 := *arr1
arr2[2] = 100
```

这样两个数组就有了不同的值,在赋值后修改 arr2 不会对 arr1 生效。
这样两个数组就有了不同的值,在赋值后修改 `arr2` 不会对 `arr1` 生效。

所以在函数中数组作为参数传入时,如 `func1(arr2)`,会产生一次数组拷贝,func1 方法不会修改原始的数组 arr2。
所以在函数中数组作为参数传入时,如 `func1(arr2)`,会产生一次数组拷贝,`func1()` 方法不会修改原始的数组 `arr2`

如果你想修改原数组,那么 arr2 必须通过&操作符以引用方式传过来,例如 func1(&arr2,下面是一个例子
如果你想修改原数组,那么 `arr2` 必须通过 `&` 操作符以引用方式传过来,例如 `func1(&arr2`,下面是一个例子

示例 7.2 [pointer_array.go](examples/chapter_7/pointer_array.go):

Expand All @@ -128,21 +128,27 @@ func main() {
fp(&ar) // passes a pointer to ar
}
```

输出结果:

[0 0 0]
&[0 0 0]

另一种方法就是生成数组切片并将其传递给函数(详见第 7.1.4 节)。
另一种方法就是生成数组切片并将其传递给函数(详见[ 7.1.4 节](07.1.md))。

**练习**

练习7.1:array_value.go: 证明当数组赋值时,发生了数组内存拷贝。
练习7.1:[array_value.go](examples\chapter_7\array_value.go):

证明当数组赋值时,发生了数组内存拷贝。

练习7.2:[for_array.go](examples\chapter_7\for_array.go):

写一个循环并用下标给数组赋值(从 0 到 15)并且将数组打印在屏幕上。

练习7.2:for_array.go: 写一个循环并用下标给数组赋值(从 0 到 15)并且将数组打印在屏幕上。
练习7.3:[fibonacci_array.go](examples\chapter_7\fibonacci_array.go):

练习7.3:fibonacci_array.go: 在第 6.6 节我们看到了一个递归计算 Fibonacci 数值的方法。但是通过数组我们可以更快的计算出 Fibonacci 数。完成该方法并打印出前 50 个 Fibonacci 数字。
[6.6 ](06.6.md) 我们看到了一个递归计算 Fibonacci 数值的方法。但是通过数组我们可以更快的计算出 Fibonacci 数。完成该方法并打印出前 50 个 Fibonacci 数字。

## 7.1.2 数组常量

Expand Down Expand Up @@ -173,7 +179,7 @@ func main() {
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`

第二种变化:

Expand Down Expand Up @@ -217,10 +223,12 @@ func main() {
```

输出结果:

&[0 0 0]
&[1 1 1]
&[2 4 8]

```
&[0 0 0]
&[1 1 1]
&[2 4 8]
```

几何点(或者数学向量)是一个使用数组的经典例子。为了简化代码通常使用一个别名:

Expand All @@ -233,7 +241,7 @@ var vec Vector3D

数组通常是一维的,但是可以用来组装成多维数组,例如:`[3][5]int``[2][2][2]float64`

内部数组总是长度相同的。Go 语言的多维数组是矩形式的(唯一的例外是切片的数组,参见第 7.2.5 节
内部数组总是长度相同的。Go 语言的多维数组是矩形式的(唯一的例外是切片的数组,参见[ 7.2.5 节](07.2.md)

示例 7.5 [multidim_array.go](examples/chapter_7/multidim_array.go)

Expand Down
Loading

0 comments on commit 30ca13a

Please sign in to comment.