Merge pull request #5 from hongruiqi/master

2.2 & 2.3 review
This commit is contained in:
astaxie
2012-08-26 18:21:04 -07:00
2 changed files with 68 additions and 35 deletions

82
2.2.md
View File

@@ -243,19 +243,33 @@ array就是数组它的定义如下`[n]type`,n表示数组的长度type表
对数组的操作和其他语言类似,都是通过`[]`来进行读取和赋值
var arr [10]int //申明了一个int类型的数组
arr[0] = 42 //数组下标是从0开始的
arr[1] = 13 //赋值操作
fmt.Printf("The first element is %d\n", arr[0]) //获取数据
由于数组的长度也是类型的一部分,比如`[3]int`与`[4]int`是不同的类型,所以数组是不能改变长度的,而且数组之间的赋值是值赋值,当把一个数组作为一个参数传入函数的时候,是这个数组的副本,而不是该数组的指针,如果要使用指针,那么就需要用到下面介绍的`slice`。
var arr [10]int //申明了一个int类型的数组
arr[0] = 42 //数组下标是从0开始的
arr[1] = 13 //赋值操作
fmt.Printf("The first element is %d\n", arr[0]) //获取数据
a := [3]int{1,2,3} //申明一个长度为3的数组
由于数组的长度也是类型的一部分,比如`[3]int`与`[4]int`是不同的类型,所以数组是不能改变长度的,而且数组之间的赋值是值赋值,当把一个数组作为一个参数传入函数的时候,是这个数组的副本,而不是该数组的指针,如果要使用指针,那么就需要用到下面介绍的`slice`。
数组申明可以使用另一种`:=`来申明
a := [3]int{1,2,3} //申明一个长度为3的数组
b := [10]int{1,2,3} //申明了一个长度为10的数组其中前面三个元素初始化为1、2、3其他默认为0
c := […]int{4,5,6} //可以省略长度采用…go会自动计算长度
也许你会说我想数组里面还是数组能实现吗当然咯GO支持嵌套数组即多维数组如下代码申明了一个二维数组
//申明了一个二维数组该数组是一个两个元素的数组然后每个元素里面是4个int的元素
double_array := [2][4]int {[4]int{1,2,3,4}, [4]int{5,6,7,8}}
//如果内部的元素和外部的一样,那么上面的申明可以简化,直接忽略内部的类型
b := [10]int{1,2,3} //申明了一个长度为10的数组其中前面三个元素初始化为1、2、3其他默认为0
easy_array :=[2][4]int{{1,2,3,4},{5,6,7,8}}
数组的分配如下所示:
![](images/2.2.array.png?raw=true)
###slice
@@ -263,7 +277,7 @@ array就是数组它的定义如下`[n]type`,n表示数组的长度type表
`slice`并不是真正意义上面的动态数组,而是一个引用类型,`slice`总是指向底层的一个`array`。`slice`的申明也可以像`array`一样只要省略size
//如果内部的元素和外部的一样,那么上面的申明可以简化,直接忽略内部的类型
//和申明array一样只是少了长度
var fslice []int
接下来我们可以申明一个slice并初始化数据如下所示
@@ -272,10 +286,10 @@ array就是数组它的定义如下`[n]type`,n表示数组的长度type表
slice可以从一个数组或者一个已经存在的slice里面再次申明`slice`通过array[i:j]来获取i是数组的开始位置j是结束位置但不包含array[j]他的长度是j-i
//申明一个含有10个字符元素的数组
var array [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
`slice`并不是真正意义上面的动态数组,而是一个引用类型,`slice`总是指向底层的一个`array`。`slice`的申明也可以像`array`一样只要省略size
//申明三个含有byte的slice
var a_slice,b_slice,c_slice []byte
//a_slice指向数组的第2个元素开始并到第五个元素结束
@@ -286,6 +300,8 @@ slice可以从一个数组或者一个已经存在的slice里面再次申明`
b_slice = array[3:5]
// b_slice的元素是: array[3], array[4]
注意slice和数组申明时的区别申明数组时方括号内写明了数组的长度或使用`...`自动计算长度而申明slice时方括号内没有任何字符
他们的数据结构如下所示
![](images/2.2.slice.png?raw=true)
@@ -300,21 +316,22 @@ slice有一些简便的操作
//申明一个数组
var array [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
他们的数据结构如下所示
![](images/2.2.slice.png?raw=true)
//申明两个slice
var a_slice,b_slice
// 演示一些简便操作
a_slice = array[:3] // 等价于a_slice = array[0:3] a_slice包含元素: a,b,c
a_slice = array[5:] // 等价于a_slice = array[5:9] a_slice包含元素: f,g,h,i,j
a_slice = array[:] // 等价于a_slice = array[0:9] 这样a_slice包含了全部的元素
//从slice获取slice
下面这个例子展示更多关于slice的操作
//申明一个数组
a_slice = array[3:7] // a_slice包含元素: d,e,f,glen=4cap=8
b_slice = a_slice[1:3] // b_slice 包含a_slice[1], a_slice[2] 也就是含有: e,f
b_slice = a_slice[:3] // b_slice 包含 a_slice[0], a_slice[1], a_slice[2] 也就是含有: d,e,f
b_slice = a_slice[0:5] // 对slice的slice可以在cap范围内扩展此时b_slice包含c,d,e,f,g
b_slice : a_slice[:] // b_slice包含所有a_slice的元素: d,e,f,g
//什么两个slice
slice是引用类型所以当引用改变其中项目的值的时候那么其他的所有引用都会改变该值例如上面的a_slice和b_slice如果修改了a_slice中项目的值那么b_slice相对应的值也会改变。
从概念上面来说slice想一个结构体这个结构体包含了三个元素
- 一个指针指向数组中slice指定的开始位置
@@ -335,22 +352,24 @@ slice下面有几个有用的内置函数
- append 向slice里面追加一个或者多个元素然后返回一个和slice一样类型的slice
- copy 函数copy 从源slice src 复制元素到目标dst并且返回复制的元素的个数
append函数会改变slice所引用的数组的内容从而影响到引用同一数组的其它slice。
但当slice中没有剩余空间(cap-len) == 0)时此时将动态分配新的数组空间返回的slice的数组指针将指向这个空间而原数组的内容将保持不变其它引用此数组的slice不受影响。
###map
map也就是python中字典的概念它的格式`map[keyType]valueType`
![](images/2.2.slice2.png?raw=true)
我们看下面的代码map的读取和设置也类似slice一样通过key来操作只是slice只有int的key而map多了很多类型可以是int可以是string
// 申明一个key是字符串值为int的字典
var numbers map[string] int
- len 获取slice的长度
- cap 获取slice的最大容量
//另一种map的申明方式
numbers := make(map[string]int)
numbers["one"] = 1 //赋值
numbers["ten"] = 10 //赋值
numbers["three"] = 3
###map
fmt.Println("第三个数字是: ", numbers["three"]) //读取数据
// 打印出来如下:
//第三个数字是: 3
@@ -362,7 +381,7 @@ map也就是python中字典的概念它的格式`map[keyType]valueType`
- 内置的len函数同样试用于map返回map拥有的key的数量
- map的值可以很方便的修改通过`numbers["one"]=11`可以很容易的把key为`one`的字典值改为11
numbers["three"] = 3
map的初始化可以通过key:val的方式初始化值同时map内置有判断是否存在key的方式
删除map的元素通过delete
@@ -381,7 +400,7 @@ map的初始化可以通过key:val的方式初始化值同时获取map内置
上面说过了map也是一种引用类型如果两个map同时指向一个底层那么一个改变另一个也相应的改变
rating := map[string]float32 {"C":5, "Go":4.5, "Python":4.5, "C++":2 }
m = make(map[string]string)
m["Hello"] = "Bonjour"
m1 = m
m1["Hello"] = "Salut" //现在m["hello"]的值已经是Salut了
@@ -393,8 +412,11 @@ map的初始化可以通过key:val的方式初始化值同时获取map内置
内建函数new 本质上说跟其他语言中的同名函数功能一样new(T) 分配了零值填充的T 类型的内存空间,并且返回其地址,一个*T类型的值。用Go的术语说它返回了一个指针指向新分配的类型T的零值。有一点非常重要new返回指针。
上面说过了map也是一种引用类型如果两个map同时指向一个底层那么一个改变另一个也相应的改变
内建函数make(T, args)与new(T)有着不同的功能。它只能创建slicemap和channel并且返回一个有初始值(非零)的T类型而不是*T。本质来讲导致这三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化。例如一个slice是一个包含指向数据内部array的指针长度和容量的三项描述符在这些项目被初始化之前slice 为nil。对于slicemap 和channelmake 初始化了内部的数据结构填充适当的值。make返回初始化后的非零值。
下面这个图详细的解释了new和make之间的区别
![](images/2.2.makenew.png?raw=true)

21
2.3.md
View File

@@ -13,7 +13,7 @@ Go里面if条件语法中不需要括号如下代码所示
fmt.Println("x is less than 10")
}
Go的if还有一个强大的地方就是条件里面允许什么一个变量,这个变量的作用域只能在该条件中,出了这个条件就不起作用了,如下所示
Go的if还有一个强大的地方就是条件里面允许申明一个变量,这个变量的作用域只能在该条件中,出了这个条件就不起作用了,如下所示
// 计算获取值x,然后根据x返回的大小判断是否大于10.
if x := computed_value(); x > 10 {
@@ -37,15 +37,25 @@ Go的if还有一个强大的地方就是条件里面允许什么一个变量
###goto
Go有goto语句——明智的使用它。用goto跳转到一定是当前函数内定义的标签。例如假设这样一个循环
Go有goto语句——明智的使用它。用goto跳转到一定是当前函数内定义的标签。例如假设这样一个循环
func myfunc() {
i := 0
Here: //这行的第一个词,以分号结束作为标签
println(i)
i++
goto Here //跳转到Here去
}
标签名是大小写敏感的。
###for
go里面最强大的一个控制逻辑就是for他即可以用来循环读取数据又可以当作while来控制逻辑还能迭代操作。它的语法如下
for expression1; expression2; expression3{
...
}
expression1、expression2、expression3都是表达式其中expression1和expression3是变量申明或者函数调用返回值之类的expression2是条件判断expression1在循环开始之前调用expression3在循环结束之后调用
一个例子比上面讲那么多更有用,那么我们看看下面的例子吧
@@ -90,6 +100,7 @@ expression1、expression2、expression3都是表达式其中expression1和exp
//break打印出来10、9、8、7、6
//continue打印出来10、9、8、7、6、4、3、2、1
break 和 continue 还可以跟着标号,用来跳到多重循环中的外层循环
for可以用于读取slice和map的数据配合range
@@ -177,4 +188,4 @@ sExpr和expr1、expr2、expr3的类型必须一致。Go的switch非常灵活。
* 下一节: [高级类型](<2.4.md>)
## LastModified
###递归函数
* $Id$