update 2.2md,2.3md,fixed 8.1md code error

This commit is contained in:
chenwenli
2012-10-29 17:18:06 +08:00
parent 3b0b1aa517
commit 3ca6160f95
3 changed files with 50 additions and 48 deletions

74
2.2.md
View File

@@ -1,12 +1,12 @@
#2.2 Go基础
这小节我们将要介绍如何定义变量、常量、Go内置类型以及一些Go程序设计中的技巧。
这小节我们将要介绍如何定义变量、常量、Go内置类型以及Go程序设计中的一些技巧。
##定义变量
Go语言里面定义变量有多种方式。
使用`var`关键字定义变量是最基本的与C语言定义变量不同的是Go语言变量名在变量类型前面:
使用`var`关键字是Go最基本的定义变量方式与C语言不同的是Go把变量类型放在变量名后面:
//定义一个名称为“variableName”类型为"type"的变量
var variableName type
@@ -29,7 +29,7 @@ Go语言里面定义变量有多种方式。
*/
var vname1, vname2, vname3 type= v1, v2, v3
你是不是觉得上面这样的定义有点复杂没关系因为Go语言的设计者也发现了我们来让它变得简单一点。我们可以直接忽略类型声明,那么上面的东西变成这样了:
你是不是觉得上面这样的定义有点繁琐没关系因为Go语言的设计者也发现了有一种写法可以让它变得简单一点。我们可以直接忽略类型声明,那么上面的代码变成这样了:
/*
定义三个变量,它们分别初始化相应的值
@@ -38,7 +38,7 @@ Go语言里面定义变量有多种方式。
*/
var vname1, vname2, vname3 = v1, v2, v3
还是觉得上面的有些复杂?好吧,我觉得也是。让我们继续简化:
你觉得上面的还是有些繁琐?好吧,我觉得。让我们继续简化:
/*
定义三个变量,它们分别初始化相应的值
@@ -47,7 +47,7 @@ Go语言里面定义变量有多种方式。
*/
vname1, vname2, vname3 := v1, v2, v3
现在是不是看上去非常的简单了?`:=`这个符号直接取代了`var``type`,这样的代码是不是很简洁?这种形式叫做简短声明。不过它有一个限制,那就是它只能用在函数内部;在函数外部使用则会无法编译通过,比如说用它来定义全局变量。
现在是不是看上去非常简洁了?`:=`这个符号直接取代了`var``type`,这种形式叫做简短声明。不过它有一个限制,那就是它只能用在函数内部;在函数外部使用则会无法编译通过,所以一般用`var`方式来定义全局变量。
`_`(下划线)是个特殊的变量名,任何赋予它的值都会被丢弃。在这个例子中,我们将值`35`赋予`b`,并同时丢弃`34`
@@ -63,29 +63,27 @@ Go对于已声明但未使用的变量会在编译阶段报错比如下面的
##常量
所谓常量也就是在编译阶段就确定下来的值而程序在运行时则无法改变该值。在Go程序中常量可定义为数值、布尔值或字符串等类型。
所谓常量,也就是在程序编译阶段就确定下来的值而程序在运行时则无法改变该值。在Go程序中常量可定义为数值、布尔值或字符串等类型。
它的语法如下:
const constantName = value
//如果需要,也可以明确指定常量的类型:
const Pi float32 = 3.1415926
下面是一些常量声明的例子:
const Pi = 3.1415926
const i = 10000
const MaxThread = 10
const prefix = 'astaxie_'
当然如果需要,也可以明确指定常量的类型:
const Pi float32 = 3.1415926
const prefix = "astaxie_"
##内置基础类型
###Boolean
在Go中布尔值的类型为`bool`可用的值是`true``false`,默认为`false`
在Go中布尔值的类型为`bool`,值是`true``false`,默认为`false`
//示例代码
var isActive bool // 全局变量声明
@@ -99,30 +97,30 @@ Go对于已声明但未使用的变量会在编译阶段报错比如下面的
###数值类型
整数类型有无符号和带符号两种。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`的别称。
整数类型有无符号和带符号两种。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`的别称。
>需要注意的一点是,这些类型的变量之间不允许互相赋值或操作,不然会在编译时引起编译器报错。
>
>如下的代码会产生错误
>
> var a int8
> var b int32
> c:=a + b
>> var a int8
>> var b int32
>> c:=a + b
>
>另外尽管int的长度是32 bit, 但int 与 int32并不可以互用。
浮点数的类型有`float32``float64`两种(没有`float`类型),默认是`float64`
这就是全部吗NoGo还支持复数。它的默认类型是`complex128`64位实数+64位虚数。如果需要小一些的也有`complex64`(32位实数+32位虚数)。复数的形式为`re + imi`,其中`re`是实数部分,`im`是虚数部分,而最后的`i`是虚数单位。下面是一个使用复数的例子:
这就是全部吗NoGo还支持复数。它的默认类型是`complex128`64位实数+64位虚数。如果需要小一些的也有`complex64`(32位实数+32位虚数)。复数的形式为`RE + IMi`,其中`RE`是实数部分,`IM`是虚数部分,而最后的`i`是虚数单位。下面是一个使用复数的例子:
var c complex64 = 5+5i
//output: (5+5i)
fmt.Printf("Value is: %v", c)
它会打印:(5+5i)
###字符串
我们在上一节中讲过Go中的字符串都是用`UTF-8`的形式编码。字符串通过用一对双引号(`""`)或反引号(`` ` ```` ` ``)括起来定义,它的类型是`string`。
我们在上一节中讲过Go中的字符串都是`UTF-8`字符集编码。字符串用一对双引号(`""`)或反引号(`` ` `` `` ` ``)括起来定义,它的类型是`string`。
//示例代码
var frenchHello string // 声明变量为字符串的一般方法
@@ -148,7 +146,7 @@ Go对于已声明但未使用的变量会在编译阶段报错比如下面的
fmt.Printf("%s\n", s2)
Go中可以使用`+`来链接两个字符串:
Go中可以使用`+`操作符来连接两个字符串:
s := "hello,"
m := " world"
@@ -157,7 +155,7 @@ Go中可以使用`+`来链接两个字符串:
修改字符串也可写为:
s := "hello"
s := "hello"
s = "c" + s[1:] // 字符串虽不能更改,但可进行切片操作
fmt.Printf("%s\n", s)
@@ -237,10 +235,10 @@ Go里面有一个关键字`iota`,这个关键字用来声明`enum`的时候采
###Go程序设计的一些规则
Go之所以会那么简洁是因为它有一些默认的行为
- 大写字母开头的变量是导出的,也就是其它包可以读取的,类似`class`中`public`的概念;小写字母开头的就是导出的
- 大写字母开头的函数也是一样,相当于`public`函数;小写字母开头的就是类似`private`
- 大写字母开头的变量是导出的,也就是其它包可以读取的,是公用变量;小写字母开头的就是不可导出的,是私有变量。
- 大写字母开头的函数也是一样,相当于`class`中的带`public`关键词的公有函数;小写字母开头的就是`private`关键词的私有函数。
##array、slicemap
##array、slicemap
###array
`array`就是数组,它的定义方式如下:
@@ -252,7 +250,8 @@ Go之所以会那么简洁是因为它有一些默认的行为
var arr [10]int // 声明了一个int类型的数组
arr[0] = 42 // 数组下标是从0开始的
arr[1] = 13 // 赋值操作
fmt.Printf("The first element is %d\n", arr[0]) // 获取数据
fmt.Printf("The first element is %d\n", arr[0]) // 获取数据返回42
fmt.Printf("The last element is %d\n", arr[9]) //返回未赋值的最后一个元素默认返回0
由于长度也是数组类型的一部分,因此`[3]int`与`[4]int`是不同的类型,数组也就不能改变长度。数组之间的赋值是值的赋值,即当把一个数组作为参数传入函数的时候,传入的其实是该数组的副本,而不是它的指针。如果要使用指针,那么就需要用到后面介绍的`slice`类型了。
@@ -264,7 +263,7 @@ Go之所以会那么简洁是因为它有一些默认的行为
c := [...]int{4, 5, 6} // 可以省略长度而采用`...`的方式Go会自动根据元素个数来计算长度
也许你会说我想数组里面还是数组能实现吗当然咯Go支持嵌套数组即多维数组。比如下面的代码就声明了一个二维数组
也许你会说,我想数组里面的值还是数组能实现吗当然咯Go支持嵌套数组即多维数组。比如下面的代码就声明了一个二维数组
// 声明了一个二维数组该数组以两个数组作为元素其中每个数组中又有4个int类型的元素
doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}
@@ -279,9 +278,9 @@ Go之所以会那么简洁是因为它有一些默认的行为
###slice
在很多应用场景中,数组并不能满足我们的需求。在刚开始我们并不知道需要多大的数组因此我们就需要“动态数组”。在Go里面这种数据结构叫`slice`
在很多应用场景中,数组并不能满足我们的需求。在初始定义数组我们并不知道需要多大的数组因此我们就需要“动态数组”。在Go里面这种数据结构叫`slice`
`slice`并不是真正意义上的动态数组,而是一个引用类型。`slice`总是指向底层的一个`array``slice`的声明也可以像`array`一样,只是不需要长度。
`slice`并不是真正意义上的动态数组,而是一个引用类型。`slice`总是指向一个底层`array``slice`的声明也可以像`array`一样,只是不需要长度。
// 和声明array一样只是少了长度
var fslice []int
@@ -306,7 +305,7 @@ Go之所以会那么简洁是因为它有一些默认的行为
b = ar[3:5]
// b的元素是ar[3]和ar[4]
>注意`slice`和数组在声明时的区别:声明数组时,方括号内写明了数组的长度或使用`...`自动计算长度,而声明``slice``时,方括号内没有任何字符。
>注意`slice`和数组在声明时的区别:声明数组时,方括号内写明了数组的长度或使用`...`自动计算长度,而声明`slice`时,方括号内没有任何字符。
它们的数据结构如下所示
@@ -316,7 +315,7 @@ slice有一些简便的操作
- `slice`的默认开始位置是0`ar[:n]`等价于`ar[0:n]`
- `slice`的第二个序列默认是数组的长度,`ar[n:]`等价于`ar[n:len(ar)]`
- `slice`如果从一个数组里面直接获取,可以这样`ar[:]`因为默认第一个序列是0第二个是数组的长度即等价于`ar[0:len(ar)]`
- 如果从一个数组里面直接获取`slice`,可以这样`ar[:]`因为默认第一个序列是0第二个是数组的长度即等价于`ar[0:len(ar)]`
下面这个例子展示了更多关于`slice`的操作:
@@ -376,8 +375,7 @@ slice有一些简便的操作
numbers["three"] = 3
fmt.Println("第三个数字是: ", numbers["three"]) // 读取数据
// 打印出来如:
// 第三个数字是: 3
// 打印出来如:第三个数字是: 3
这个`map`就像我们平常看到的表格一样,左边列是`key`,右边列是值
@@ -416,15 +414,19 @@ slice有一些简便的操作
`make`用于内建类型(`map`、`slice` 和`channel`)的内存分配。`new`用于各种类型的内存分配。
内建函数`new`本质上说跟其它语言中的同名函数功能一样:`new(T)`分配了零值填充的`T`类型的内存空间,并且返回其地址,即一个`*T`类型的值。用Go的术语说它返回了一个指针指向新分配的类型`T`的零值。有一点非常重要:`new`返回指针。
内建函数`new`本质上说跟其它语言中的同名函数功能一样:`new(T)`分配了零值填充的`T`类型的内存空间,并且返回其地址,即一个`*T`类型的值。用Go的术语说它返回了一个指针指向新分配的类型`T`的零值。有一点非常重要:
内建函数`make(T, args)`与`new(T)`有着不同的功能,它只能创建`slice`、`map`和`channel`,并且返回一个有初始值(非零)的`T`类型,而不是`*T`。本质来讲,导致这三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化。例如,一个`slice`,是一个包含指向数据(内部`array`)的指针、长度和容量的三项描述符;在这些项目被初始化之前,`slice`为`nil`。对于`slice`、`map`和`channel`来说,`make`初始化了内部的数据结构,填充适当的值。`make`返回初始化后的(非零)值
>`new`返回指针
内建函数`make(T, args)`与`new(T)`有着不同的功能make只能创建`slice`、`map`和`channel`,并且返回一个有初始值(非零)的`T`类型,而不是`*T`。本质来讲,导致这三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化。例如,一个`slice`,是一个包含指向数据(内部`array`)的指针、长度和容量的三项描述符;在这些项目被初始化之前,`slice`为`nil`。对于`slice`、`map`和`channel`来说,`make`初始化了内部的数据结构,填充适当的值。
>`make`返回初始化后的(非零)值。
下面这个图详细的解释了`new`和`make`之间的区别。
![](images/2.2.makenew.png?raw=true)
关于“零值”,所指并非是空值,而是一种“变量未填充前”的默认值通常为 0。
关于“零值”,所指并非是空值,而是一种“变量未填充前”的默认值通常为0。
此处罗列 部分类型 的 “零值”
int 0