11# 2.2 Go基础  
22
3- 这小节我们将要介绍如何定义变量、常量、Go内置类型以及一些Go程序设计中的技巧 。
3+ 这小节我们将要介绍如何定义变量、常量、Go内置类型以及Go程序设计中的一些技巧 。
44
55## 定义变量  
66
77Go语言里面定义变量有多种方式。
88
9- 使用` var ` 关键字定义变量是最基本的,与C语言定义变量不同的是,Go语言变量名在变量类型前面 :
9+ 使用` var ` 关键字是Go最基本的定义变量方式,与C语言不同的是Go把变量类型放在变量名后面 :
1010
1111	//定义一个名称为“variableName”,类型为"type"的变量 
1212	var variableName type 
@@ -29,7 +29,7 @@ Go语言里面定义变量有多种方式。
2929	*/ 
3030	var vname1, vname2, vname3 type= v1, v2, v3 
3131
32- 你是不是觉得上面这样的定义有点复杂 ?没关系,因为Go语言的设计者也发现了,我们来让它变得简单一点 。我们可以直接忽略类型声明,那么上面的东西变成这样了 :
32+ 你是不是觉得上面这样的定义有点繁琐 ?没关系,因为Go语言的设计者也发现了,有一种写法可以让它变得简单一点 。我们可以直接忽略类型声明,那么上面的代码变成这样了 :
3333
3434	/* 
3535		定义三个变量,它们分别初始化相应的值 
@@ -38,7 +38,7 @@ Go语言里面定义变量有多种方式。
3838	*/ 
3939	var vname1, vname2, vname3 = v1, v2, v3 
4040
41- 你还是觉得上面的有些复杂 ?好吧,我觉得也是 。让我们继续简化:
41+ 你觉得上面的还是有些繁琐 ?好吧,我也觉得 。让我们继续简化:
4242
4343	/* 
4444		定义三个变量,它们分别初始化相应的值 
@@ -47,7 +47,7 @@ Go语言里面定义变量有多种方式。
4747	*/ 
4848	vname1, vname2, vname3 := v1, v2, v3 
4949
50- 现在是不是看上去非常的简单了 ?` := ` 这个符号直接取代了` var ` 和` type ` ,这样的代码是不是很简洁? 这种形式叫做简短声明。不过它有一个限制,那就是它只能用在函数内部;在函数外部使用则会无法编译通过,比如说用它来定义全局变量 。
50+ 现在是不是看上去非常简洁了 ?` := ` 这个符号直接取代了` var ` 和` type ` , 这种形式叫做简短声明。不过它有一个限制,那就是它只能用在函数内部;在函数外部使用则会无法编译通过,所以一般用 ` var ` 方式来定义全局变量 。
5151
5252` _ ` (下划线)是个特殊的变量名,任何赋予它的值都会被丢弃。在这个例子中,我们将值` 35 ` 赋予` b ` ,并同时丢弃` 34 ` :
5353
@@ -63,29 +63,27 @@ Go对于已声明但未使用的变量会在编译阶段报错,比如下面的
6363
6464## 常量  
6565
66- 所谓常量,也就是在编译阶段就确定下来的值 ,而程序在运行时则无法改变该值。在Go程序中,常量可定义为数值、布尔值或字符串等类型。
66+ 所谓常量,也就是在程序编译阶段就确定下来的值 ,而程序在运行时则无法改变该值。在Go程序中,常量可定义为数值、布尔值或字符串等类型。
6767
6868它的语法如下:
6969
7070	const constantName = value 
71+ 	//如果需要,也可以明确指定常量的类型: 
72+ 	const Pi float32 = 3.1415926 
7173
7274下面是一些常量声明的例子:
7375
7476	const Pi = 3.1415926 
7577	const i = 10000 
7678	const MaxThread = 10 
77- 	const prefix = 'astaxie_' 
78- 
79- 当然如果需要,也可以明确指定常量的类型:
80- 
81- 	const Pi float32 = 3.1415926 
79+ 	const prefix = "astaxie_" 
8280
8381
8482## 内置基础类型  
8583
8684### Boolean  
8785
88- 在Go中,布尔值的类型为` bool ` ,可用的值是 ` true ` 或` false ` ,默认为` false ` 。
86+ 在Go中,布尔值的类型为` bool ` ,值是 ` true ` 或` false ` ,默认为` false ` 。
8987
9088	//示例代码 
9189	var isActive bool  // 全局变量声明 
@@ -99,30 +97,30 @@ Go对于已声明但未使用的变量会在编译阶段报错,比如下面的
9997
10098### 数值类型  
10199
102- 整数类型有无符号和带符号两种。Go同时支持` int ` 和` uint ` ,这两种类型的长度相同,但具体长度取决于编译器的实现。当前的gc和gccgo编译器在32位和64位平台上都使用32位来表示 ` int ` 和` uint ` ,但未来在64位平台上可能增加到64位。Go里面也有直接定义好位数的类型:` rune ` , ` int8 ` , ` int16 ` , ` int32 ` , ` int64 ` 和` byte ` , ` uint8 ` , ` uint16 ` , ` uint32 ` , ` uint64 ` 。` rune ` 是` int32 ` 的别称,` byte ` 是` uint8 ` 的别称。
100+ 整数类型有无符号和带符号两种。Go同时支持` int ` 和` uint ` ,这两种类型的长度相同,但具体长度取决于不同编译器的实现。当前的gcc和gccgo编译器在32位和64位平台上都使用32位来表示 ` int ` 和` uint ` ,但未来在64位平台上可能增加到64位。Go里面也有直接定义好位数的类型:` rune ` , ` int8 ` , ` int16 ` , ` int32 ` , ` int64 ` 和` byte ` , ` uint8 ` , ` uint16 ` , ` uint32 ` , ` uint64 ` 。其中 ` rune ` 是` int32 ` 的别称,` byte ` 是` uint8 ` 的别称。
103101
104102> 需要注意的一点是,这些类型的变量之间不允许互相赋值或操作,不然会在编译时引起编译器报错。
105103> 
106104> 如下的代码会产生错误
107105> 
108- > 	var a int8   
109- > 	var b int32   
110- > 	c:=a + b   
106+ >> 	var a int8    
107+ >> 	var b int32    
108+ >> 	c:=a + b   
109+ >  
111110> 另外,尽管int的长度是32 bit, 但int 与 int32并不可以互用。
112111
113112浮点数的类型有` float32 ` 和` float64 ` 两种(没有` float ` 类型),默认是` float64 ` 。
114113
115- 这就是全部吗?No!Go还支持复数。它的默认类型是` complex128 ` (64位实数+64位虚数)。如果需要小一些的,也有` complex64 ` (32位实数+32位虚数)。复数的形式为` re  + imi ` ,其中` re ` 是实数部分,` im ` 是虚数部分,而最后的` i ` 是虚数单位。下面是一个使用复数的例子:
114+ 这就是全部吗?No!Go还支持复数。它的默认类型是` complex128 ` (64位实数+64位虚数)。如果需要小一些的,也有` complex64 ` (32位实数+32位虚数)。复数的形式为` RE  + IMi ` ,其中` RE ` 是实数部分,` IM ` 是虚数部分,而最后的` i ` 是虚数单位。下面是一个使用复数的例子:
116115
117116	var c complex64 = 5+5i 
118- 
117+ 	 //output: (5+5i) 
119118	fmt.Printf("Value is: %v", c) 
120119
121- 它会打印:(5+5i)
122120
123121### 字符串  
124122
125- 我们在上一节中讲过,Go中的字符串都是用 ` UTF-8 ` 的形式编码的。字符串通过用一对双引号 (` "" ` )或反引号(``  ` ```` `  `` )括起来定义,它的类型是` string ` 。
123+ 我们在上一节中讲过,Go中的字符串都是采用 ` UTF-8 ` 字符集编码。字符串是用一对双引号 (` "" ` )或反引号(``  `  ``   ``  `  `` )括起来定义,它的类型是` string ` 。
126124
127125	//示例代码 
128126	var frenchHello string  // 声明变量为字符串的一般方法 
@@ -148,7 +146,7 @@ Go对于已声明但未使用的变量会在编译阶段报错,比如下面的
148146	fmt.Printf("%s\n", s2) 
149147
150148
151- Go中可以使用` + ` 来链接两个字符串 :
149+ Go中可以使用` + ` 操作符来连接两个字符串 :
152150
153151	s := "hello," 
154152	m := " world" 
@@ -157,7 +155,7 @@ Go中可以使用`+`来链接两个字符串:
157155
158156修改字符串也可写为:
159157
160- 	s := "hello" 
158+ 	s := "hello"	  
161159	s = "c" + s[1:] // 字符串虽不能更改,但可进行切片操作 
162160	fmt.Printf("%s\n", s) 
163161
@@ -237,8 +235,8 @@ Go里面有一个关键字`iota`,这个关键字用来声明`enum`的时候采
237235
238236### Go程序设计的一些规则  
239237Go之所以会那么简洁,是因为它有一些默认的行为:
240- -  大写字母开头的变量是已导出的 ,也就是其它包可以读取的,类似 ` class ` 中 ` public ` 的概念;小写字母开头的就是未导出的 
241- -  大写字母开头的函数也是一样,相当于` public ` 的函数;小写字母开头的就是类似 ` private ` 
238+ -  大写字母开头的变量是可导出的 ,也就是其它包可以读取的,是公用变量;小写字母开头的就是不可导出的,是私有变量。 
239+ -  大写字母开头的函数也是一样,相当于` class ` 中的带 ` public ` 关键词的公有函数;小写字母开头的就是有 ` private ` 关键词的私有函数。 
242240
243241## array、slice、map  
244242
@@ -252,7 +250,8 @@ Go之所以会那么简洁,是因为它有一些默认的行为:
252250	var arr [10]int  // 声明了一个int类型的数组 
253251	arr[0] = 42      // 数组下标是从0开始的 
254252	arr[1] = 13      // 赋值操作 
255- 	fmt.Printf("The first element is %d\n", arr[0])  // 获取数据 
253+ 	fmt.Printf("The first element is %d\n", arr[0])  // 获取数据,返回42 
254+ 	fmt.Printf("The last element is %d\n", arr[9]) //返回未赋值的最后一个元素,默认返回0 
256255
257256由于长度也是数组类型的一部分,因此` [3]int ` 与` [4]int ` 是不同的类型,数组也就不能改变长度。数组之间的赋值是值的赋值,即当把一个数组作为参数传入函数的时候,传入的其实是该数组的副本,而不是它的指针。如果要使用指针,那么就需要用到后面介绍的` slice ` 类型了。
258257
@@ -264,7 +263,7 @@ Go之所以会那么简洁,是因为它有一些默认的行为:
264263
265264	c := [...]int{4, 5, 6} // 可以省略长度而采用`...`的方式,Go会自动根据元素个数来计算长度 
266265
267- 也许你会说,我想数组里面还是数组 ,能实现吗?当然咯,Go支持嵌套数组,即多维数组。比如下面的代码就声明了一个二维数组:
266+ 也许你会说,我想数组里面的值还是数组 ,能实现吗?当然咯,Go支持嵌套数组,即多维数组。比如下面的代码就声明了一个二维数组:
268267
269268    // 声明了一个二维数组,该数组以两个数组作为元素,其中每个数组中又有4个int类型的元素 
270269    doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}} 
@@ -279,9 +278,9 @@ Go之所以会那么简洁,是因为它有一些默认的行为:
279278
280279### slice  
281280
282- 在很多应用场景中,数组并不能满足我们的需求。在刚开始时 ,我们并不知道需要多大的数组,因此我们就需要“动态数组”。在Go里面这种数据结构叫` slice ` 
281+ 在很多应用场景中,数组并不能满足我们的需求。在初始定义数组时 ,我们并不知道需要多大的数组,因此我们就需要“动态数组”。在Go里面这种数据结构叫` slice ` 
283282
284- ` slice ` 并不是真正意义上的动态数组,而是一个引用类型。` slice ` 总是指向底层的一个 ` array ` ,` slice ` 的声明也可以像` array ` 一样,只是不需要长度。
283+ ` slice ` 并不是真正意义上的动态数组,而是一个引用类型。` slice ` 总是指向一个底层 ` array ` ,` slice ` 的声明也可以像` array ` 一样,只是不需要长度。
285284
286285	// 和声明array一样,只是少了长度 
287286	var fslice []int 
@@ -306,7 +305,7 @@ Go之所以会那么简洁,是因为它有一些默认的行为:
306305	b = ar[3:5] 
307306	// b的元素是:ar[3]和ar[4] 
308307
309- > 注意` slice ` 和数组在声明时的区别:声明数组时,方括号内写明了数组的长度或使用` ... ` 自动计算长度,而声明``  slice ` `
308+ > 注意` slice ` 和数组在声明时的区别:声明数组时,方括号内写明了数组的长度或使用` ... ` 自动计算长度,而声明` slice ` 时,方括号内没有任何字符。
310309
311310它们的数据结构如下所示
312311
@@ -316,7 +315,7 @@ slice有一些简便的操作
316315
317316 -  ` slice ` 的默认开始位置是0,` ar[:n] ` 等价于` ar[0:n] ` 
318317 -  ` slice ` 的第二个序列默认是数组的长度,` ar[n:] ` 等价于` ar[n:len(ar)] ` 
319-  -  ` slice ` 如果从一个数组里面直接获取 ,可以这样` ar[:] ` ,因为默认第一个序列是0,第二个是数组的长度,即等价于` ar[0:len(ar)] ` 
318+  -  如果从一个数组里面直接获取 ` slice ` ,可以这样` ar[:] ` ,因为默认第一个序列是0,第二个是数组的长度,即等价于` ar[0:len(ar)] ` 
320319
321320下面这个例子展示了更多关于` slice ` 的操作:
322321
@@ -376,8 +375,7 @@ slice有一些简便的操作
376375	numbers["three"] = 3 
377376
378377	fmt.Println("第三个数字是: ", numbers["three"]) // 读取数据 
379- 	// 打印出来如下: 
380- 	// 第三个数字是: 3 
378+ 	// 打印出来如:第三个数字是: 3 
381379
382380这个` map ` 就像我们平常看到的表格一样,左边列是` key ` ,右边列是值
383381
@@ -416,15 +414,19 @@ slice有一些简便的操作
416414
417415` make ` 用于内建类型(` map ` 、` slice `  和` channel ` )的内存分配。` new ` 用于各种类型的内存分配。
418416
419- 内建函数` new ` 本质上说跟其它语言中的同名函数功能一样:` new(T) ` 分配了零值填充的` T ` 类型的内存空间,并且返回其地址,即一个` *T ` 类型的值。用Go的术语说,它返回了一个指针,指向新分配的类型` T ` 的零值。有一点非常重要:` new ` 返回指针。
417+ 内建函数` new ` 本质上说跟其它语言中的同名函数功能一样:` new(T) ` 分配了零值填充的` T ` 类型的内存空间,并且返回其地址,即一个` *T ` 类型的值。用Go的术语说,它返回了一个指针,指向新分配的类型` T ` 的零值。有一点非常重要:
418+ 
419+ > ` new ` 返回指针。
420+ 
421+ 内建函数` make(T, args) ` 与` new(T) ` 有着不同的功能,make只能创建` slice ` 、` map ` 和` channel ` ,并且返回一个有初始值(非零)的` T ` 类型,而不是` *T ` 。本质来讲,导致这三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化。例如,一个` slice ` ,是一个包含指向数据(内部` array ` )的指针、长度和容量的三项描述符;在这些项目被初始化之前,` slice ` 为` nil ` 。对于` slice ` 、` map ` 和` channel ` 来说,` make ` 初始化了内部的数据结构,填充适当的值。
420422
421- 内建函数 ` make(T, args) ` 与 ` new(T) ` 有着不同的功能,它只能创建 ` slice ` 、 ` map ` 和 ` channel ` ,并且返回一个有初始值(非零)的 ` T ` 类型,而不是 ` *T ` 。本质来讲,导致这三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化。例如,一个 ` slice ` ,是一个包含指向数据(内部 ` array ` )的指针、长度和容量的三项描述符;在这些项目被初始化之前, ` slice ` 为 ` nil ` 。对于 ` slice ` 、 ` map ` 和 ` channel ` 来说, ` make ` 初始化了内部的数据结构,填充适当的值。 ` make ` 返回初始化后的(非零)值。
423+ > ` make ` 返回初始化后的(非零)值。
422424
423425下面这个图详细的解释了` new ` 和` make ` 之间的区别。
424426
425427![ ] ( images/2.2.makenew.png?raw=true ) 
426428
427- 关于“零值”,所指并非是空值,而是一种“变量未填充前”的默认值。通常为 0 。
429+ 关于“零值”,所指并非是空值,而是一种“变量未填充前”的默认值,通常为0 。
428430此处罗列 部分类型 的 “零值”
429431
430432    int     0 
0 commit comments