精校:7.1

This commit is contained in:
Unknwon
2015-07-27 10:23:59 +08:00
parent 1c6be233fc
commit e705814766
2 changed files with 164 additions and 124 deletions

View File

@@ -15,4 +15,4 @@ Golang 编程245386165
|更新日期 |更新内容 |更新日期 |更新内容
|----------|------------------ |----------|------------------
|2015-07-20|6.6 递归函数 |2015-07-27|7.1 声明和初始化

View File

@@ -3,26 +3,33 @@
##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 语言中是相似的)。元素的数目,也称为长度或者数组大小必须是固定的并且在声明该数组时就给出(编译时需要知道数组长度以便分配内存);数组长度最大为 2Gb。 数组元素可以通过 **索引**(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0第二个索引为 1以此类推。数组以 0 开始在所有类 C 语言中是相似的)。元素的数目,也称为长度或者数组大小必须是固定的并且在声明该数组时就给出(编译时需要知道数组长度以便分配内存);数组长度最大为 2Gb。
声明的格式是: `var identifier [len]type` 声明的格式是:
例如: `var arr1 [5]int` ```go
var identifier [len]type
```
在内存中的结构是:![](images/7.1_fig7.1.png?raw=true) 例如:
每个元素是一个整形值当声明数组时所有的元素都会被自动初始化为默认值0. ```go
var arr1 [5]int
```
arr1 的长度是 5索引范围从 0 到 len(arr1)-1 在内存中的结构是:![](../images/7.1_fig7.1.png?raw=true)
第一个元素是 arr1[0],第三个元素是 arr1[2];总体来说索引 i 代表的元素是 arr1[i],最后一个元素是 arr1[len(arr1)-1] 个元素是一个整形值,当声明数组时所有的元素都会被自动初始化为默认值 0
对索引项为 i 的数组元素赋值可以这么操作arr[i] = value所以数组是 **可变的** arr1 的长度是 5索引范围从 0 到 `len(arr1)-1`
只有有效的索引可以被使用,当使用等于或者大于 len(arr1) 的索引时:如果编译器可以检测到,会给出索引超限的提示信息;如果检测不到的话编译会通过而运行时会 panic:(参考 [第 13 章](13.0.md) 第一个元素是 `arr1[0]`,第三个元素是 `arr1[2]`;总体来说索引 i 代表的元素是 `arr1[i]`,最后一个元素是 `arr1[len(arr1)-1]`
对索引项为 i 的数组元素赋值可以这么操作:`arr[i] = value`,所以数组是 **可变的**
只有有效的索引可以被使用,当使用等于或者大于 `len(arr1)` 的索引时:如果编译器可以检测到,会给出索引超限的提示信息;如果检测不到的话编译会通过而运行时会 panic:(参考 [第 13 章](13.0.md)
runtime error: index out of range runtime error: index out of range
@@ -34,6 +41,7 @@ arr1 的长度是 5索引范围从 0 到 len(arr1)-1
示例 7.1 [for_arrays.go](examples/chapter_7/for_arrays.go) 示例 7.1 [for_arrays.go](examples/chapter_7/for_arrays.go)
```go
package main package main
import "fmt" import "fmt"
@@ -48,6 +56,7 @@ arr1 的长度是 5索引范围从 0 到 len(arr1)-1
fmt.Printf("Array at index %d is %d\n", i, arr1[i]) fmt.Printf("Array at index %d is %d\n", i, arr1[i])
} }
} }
```
输出结果: 输出结果:
@@ -57,48 +66,57 @@ arr1 的长度是 5索引范围从 0 到 len(arr1)-1
Array at index 3 is 6 Array at index 3 is 6
Array at index 4 is 8 Array at index 4 is 8
for循环中的条件非常重要i < len(arr1)如果写成i <= len(arr1)的话会产生越界错误 for 循环中的条件非常重要`i < len(arr1)`,如果写成 `i <= len(arr1)` 的话会产生越界错误
IDIOM: IDIOM:
```go
for i:=0; i < len(arr1); i++ for i:=0; i < len(arr1); i++
arr1[i] = ... arr1[i] = ...
} }
```
也可以使用 for-range 的生成方式: 也可以使用 for-range 的生成方式:
IDIOM: IDIOM:
```go
for i,_:= range arr1 { for i,_:= range arr1 {
... ...
} }
```
在这里i也是数组的索引当然这两种 for 结构对于切片(slices)参考 [第 7 章](07.2.md)来说也同样适用 在这里i也是数组的索引。当然这两种 for 结构对于切片slices参考 [第 7 章](07.2.md)来说也同样适用
**问题 7.1** 下面代码段的输出是什么? **问题 7.1** 下面代码段的输出是什么?
```go
a := [...]string{"a", "b", "c", "d"} a := [...]string{"a", "b", "c", "d"}
for i := range a { for i := range a {
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`
这样的结果就是当把一个数组赋值给另一个时,需要在做一次数组内存的拷贝操作。例如: 这样的结果就是当把一个数组赋值给另一个时,需要在做一次数组内存的拷贝操作。例如:
```go
arr2 := arr1 arr2 := arr1
arr2[2] = 100 arr2[2] = 100
```
这样两个数组就有了不同的值,在赋值后修改 arr2 不会对 arr1 生效。 这样两个数组就有了不同的值,在赋值后修改 arr2 不会对 arr1 生效。
所以在函数中数组作为参数传入时 func1(arr2)会产生一次数组拷贝func1 方法不会修改原始的数组 arr2 所以在函数中数组作为参数传入时,如 `func1(arr2)`会产生一次数组拷贝func1 方法不会修改原始的数组 arr2
如果你想修改原数组,那么 arr2 必须通过&操作符以引用方式传过来,例如 func1(&arr2下面是一个例子 如果你想修改原数组,那么 arr2 必须通过&操作符以引用方式传过来,例如 func1(&arr2下面是一个例子
Example 7.2 [pointer_array.go](examples/chapter_7/pointer_array.go): 示例 7.2 [pointer_array.go](examples/chapter_7/pointer_array.go):
```go
package main package main
import "fmt" import "fmt"
func f(a [3]int) { fmt.Println(a) } func f(a [3]int) { fmt.Println(a) }
@@ -109,13 +127,14 @@ Example 7.2 [pointer_array.go](examples/chapter_7/pointer_array.go):
f(ar) // passes a copy of ar f(ar) // passes a copy of ar
fp(&ar) // passes a pointer to ar fp(&ar) // passes a pointer to ar
} }
```
输出结果: 输出结果:
[0 0 0] [0 0 0]
&[0 0 0] &[0 0 0]
另一种方法就是生成数组切片并将其传递给函数参见传递数组参数给函数7.1.4节 另一种方法就是生成数组切片并将其传递给函数(详见第 7.1.4 节)。
**练习** **练习**
@@ -123,14 +142,15 @@ Example 7.2 [pointer_array.go](examples/chapter_7/pointer_array.go):
练习7.2for_array.go: 写一个循环并用下标给数组赋值(从 0 到 15并且将数组打印在屏幕上。 练习7.2for_array.go: 写一个循环并用下标给数组赋值(从 0 到 15并且将数组打印在屏幕上。
练习7.3fibonacci_array.go: 在6.6节我们看到了一个递归计算Fibonacci数值的方法但是通过数组我们可以更快的计算出Fibonacci完成该方法并打印出前50Fibonacci数字 练习7.3fibonacci_array.go: 在第 6.6 节我们看到了一个递归计算 Fibonacci 数值的方法但是通过数组我们可以更快的计算出 Fibonacci 数。完成该方法并打印出前 50Fibonacci 数字
## 7.1.2 数组常量 ## 7.1.2 数组常量
如果数组值已经提前知道了,那么可以通过 **数组常量** 的方法来初始化数组,而不用依次使用 `[]=` 方法(所有的组成元素都有相同的常量语法)。 如果数组值已经提前知道了,那么可以通过 **数组常量** 的方法来初始化数组,而不用依次使用 `[]=` 方法(所有的组成元素都有相同的常量语法)。
Example 7.3 [array_literals.go](examples/chapter_7/array_literals.go) 示例 7.3 [array_literals.go](examples/chapter_7/array_literals.go)
```go
package main package main
import "fmt" import "fmt"
@@ -145,18 +165,29 @@ Example 7.3 [array_literals.go](examples/chapter_7/array_literals.go)
fmt.Printf("Person at %d is %s\n", i, arrKeyValue[i]) fmt.Printf("Person at %d is %s\n", i, arrKeyValue[i])
} }
} }
```
第一种变化 `var arrAge = [5]int{18, 20, 15, 22, 16}` 第一种变化
```go
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}` 第二种变化
```go
var arrLazy = [...]int{5, 6, 7, 8, 22}
```
`...` 可同样可以忽略,从技术上说它们其实变化成了切片。 `...` 可同样可以忽略,从技术上说它们其实变化成了切片。
第三种变化:`key: value syntax` 第三种变化:`key: value syntax`
```go
var arrKeyValue = [5]string{3: "Chris", 4: "Ron"} var arrKeyValue = [5]string{3: "Chris", 4: "Ron"}
```
只有索引 3 和 4 被赋予实际的值,其他元素都被设置为空的字符串,所以输出结果为: 只有索引 3 和 4 被赋予实际的值,其他元素都被设置为空的字符串,所以输出结果为:
@@ -170,8 +201,9 @@ Example 7.3 [array_literals.go](examples/chapter_7/array_literals.go)
你可以取任意数组常量的地址来作为指向新实例的指针。 你可以取任意数组常量的地址来作为指向新实例的指针。
Example 7.4 [pointer_array2.go](examples/chapter_7/pointer_array2.go) 示例 7.4 [pointer_array2.go](examples/chapter_7/pointer_array2.go)
```go
package main package main
import "fmt" import "fmt"
@@ -182,6 +214,7 @@ Example 7.4 [pointer_array2.go](examples/chapter_7/pointer_array2.go)
fp(&[3]int{i, i * i, i * i * i}) fp(&[3]int{i, i * i, i * i * i})
} }
} }
```
输出结果: 输出结果:
@@ -191,17 +224,20 @@ Example 7.4 [pointer_array2.go](examples/chapter_7/pointer_array2.go)
几何点(或者数学向量)是一个使用数组的经典例子。为了简化代码通常使用一个别名: 几何点(或者数学向量)是一个使用数组的经典例子。为了简化代码通常使用一个别名:
```go
type Vector3D [3]float32 type Vector3D [3]float32
var vec Vector3D var vec Vector3D
```
## 7.1.3 多维数组 ## 7.1.3 多维数组
数组通常是1维的但是可以用来组装成多维数组例如`[3][5]int``[2][2][2]float64` 数组通常是维的但是可以用来组装成多维数组,例如:`[3][5]int``[2][2][2]float64`
内部数组总是长度相同的。Go 语言的多维数组是矩形式的(唯一的例外是切片的数组,参见第 7.2.5 节)。 内部数组总是长度相同的。Go 语言的多维数组是矩形式的(唯一的例外是切片的数组,参见第 7.2.5 节)。
Example 7.5 [multidim_array.go](examples/chapter_7/multidim_array.go) 示例 7.5 [multidim_array.go](examples/chapter_7/multidim_array.go)
```go
package main package main
const ( const (
WIDTH = 1920 WIDTH = 1920
@@ -218,6 +254,7 @@ Example 7.5 [multidim_array.go](examples/chapter_7/multidim_array.go)
} }
} }
} }
```
## 7.1.4 将数组传递给函数 ## 7.1.4 将数组传递给函数
@@ -228,8 +265,9 @@ Example 7.5 [multidim_array.go](examples/chapter_7/multidim_array.go)
接下来的例子阐明了第一种方法: 接下来的例子阐明了第一种方法:
Example 7.6 [array_sum.go](examples/chapter_7/array_sum.go) 示例 7.6 [array_sum.go](examples/chapter_7/array_sum.go)
```go
package main package main
import "fmt" import "fmt"
@@ -246,11 +284,13 @@ Example 7.6 [array_sum.go](examples/chapter_7/array_sum.go)
} }
return return
} }
```
输出结果: 输出结果:
The sum of the array is: 24.600000 The sum of the array is: 24.600000
但这在 Go 中并不常用通常使用切片。(参考 [第 7](07.2.md) 但这在 Go 中并不常用,通常使用切片(参考 [第 7.2 节](07.2.md))。
## 链接 ## 链接