go语言有一个获取远程包的工具就是go get,目前go get支持多数开源社区(例如:GitHub、googlecode、bitbucket、Launchpad)
这个命令在内部实际上分成了两步操作:第一步是下载源码包,第二步是执行go install
go get github.com/astaxie/beedb
go get -u 参数可以自动更新包,而且当go get的时候会自动获取该包依赖的其他第三方包
go test
执行这个命令,会自动读取源码目录下面名为*_test.go的文件,生成并运行测试用的可执行文件。
-v 显示测试的详细命令
godoc
godoc -http=:8080
浏览器中打开127.0.0.1:8080,会看到一个golang.org的本地copy版本,可以查询pkg文档等其它内容
详解
package <pkgName>(在我们的例子中是package main)这一行告诉我们当前文件属于哪个包,而包名main则告诉我们它是一个可独立运行的包,它在编译后会产生可执行文件。除了main包之外,其它的包最后都会生成*.a文件(也就是包文件)并放置在$GOPATH/pkg/$GOOS_$GOARCH中(以Mac为例就是$GOPATH/pkg/darwin_amd64)。
每一个可独立运行的Go程序,必定包含一个
package main,在这个main包中必定包含一个入口函数main,而这个函数既没有参数,也没有返回值。
函数是通过<pkgName>.<funcName>的方式调用的
前面提到过,包名和包所在的文件夹名可以是不同的,此处的<pkgName>即为通过package <pkgName>声明的包名,而非文件夹名。
使用var关键字是Go最基本的定义变量方式,与C语言不同的是Go把变量类型放在变量名后面:
_(下划线)是个特殊的变量名,任何赋予它的值都会被丢弃。
Go对于已声明但未使用的变量会在编译阶段报错
在Go中,布尔值的类型为bool,值是true或false,默认为false。
错误类型
Go内置有一个error类型,专门用来处理错误信息,Go的package里面还专门有一个包errors来处理错误:
err := errors.New("emit macho dwarf: elf header corrupted")
if err != nil {
fmt.Print(err)
}
Go程序设计的一些规则
- 大写字母开头的变量是可导出的,也就是其它包可以读取的,是公有变量;小写字母开头的就是不可导出的,是私有变量。
- 大写字母开头的函数也是一样,相当于
class中的带public关键词的公有函数;小写字母开头的就是有private关键词的私有函数。
array
array就是数组,它的定义方式如下:
var arr [n]type
slice
slice并不是真正意义上的动态数组,而是一个引用类型。slice总是指向一个底层array,slice的声明也可以像array一样,只是不需要长度。
// 和声明array一样,只是少了长度
var fslice []int
注意slice和数组在声明时的区别:声明数组时,方括号内写明了数组的长度或使用...自动计算长度,而声明slice时,方括号内没有任何字符。
slice是引用类型,所以当引用改变其中元素的值时,其它的所有引用都会改变该值
对于slice有几个有用的内置函数:
len获取slice的长度cap获取slice的最大容量append向slice里面追加一个或者多个元素,然后返回一个和slice一样类型的slicecopy函数copy从源slice的src中复制元素到目标dst,并且返回复制的元素的个数
map
map`也就是Python中字典的概念,它的格式为`map[keyType]valueType
// 声明一个key是字符串,值为int的字典,这种方式的声明需要在使用之前使用make初始化
var numbers map[string]int
// 另一种map的声明方式
numbers = make(map[string]int)
使用map过程中需要注意的几点:
map是无序的,每次打印出来的map都会不一样,它不能通过index获取,而必须通过key获取map的长度是不固定的,也就是和slice一样,也是一种引用类型- 内置的
len函数同样适用于map,返回map拥有的key的数量 map的值可以很方便的修改,通过numbers["one"]=11可以很容易的把key为one的字典值改为11map和其他基本型别不同,它不是thread-safe,在多个go-routine存取时,必须使用mutex lock机制
make、new操作
make用于内建类型(map、slice 和channel)的内存分配。new用于各种类型的内存分配。
new返回指针。
零值
关于“零值”,所指并非是空值,而是一种“变量未填充前”的默认值,通常为0。 此处罗列 部分类型 的 “零值”
int 0
int8 0
int32 0
int64 0
uint 0x0
rune 0 //rune的实际类型是 int32
byte 0x0 // byte的实际类型是 uint8
float32 0 //长度为 4 byte
float64 0 //长度为 8 byte
bool false
string ""
goto
Go有goto语句——请明智地使用它。用goto跳转到必须在当前函数内定义的标签。
for
Go里面最强大的一个控制逻辑就是for,它既可以用来循环读取数据,又可以当作while来控制逻辑,还能迭代操作。
for a; b; c {
//...
}
a、b和c都是表达式,其中a和c是变量声明或者函数调用返回值之类的,b是用来条件判断,a在循环开始之前调用,c在每轮循环结束之时调用。
在循环里面有两个关键操作break和continue ,break操作是跳出当前循环,continue是跳过本次循环。当嵌套过深的时候,break可以配合标签使用,即跳转至标签所指定的位置。
break和continue还可以跟着标号,用来跳到多重循环中的外层循环
for配合range可以用于读取slice和map的数据
由于 Go 支持 “多值返回”, 而对于“声明而未被调用”的变量, 编译器会报错, 在这种情况下, 可以使用_来丢弃不需要的返回值
函数
函数是Go里面的核心设计,它通过关键字func来声明,它的格式如下:
func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) {
//这里是处理逻辑代码
//返回多个值
return value1, value2
}
上面的代码我们看出
- 关键字
func用来声明一个函数funcName - 函数可以有一个或者多个参数,每个参数后面带有类型,通过
,分隔 - 函数可以返回多个值
- 上面返回值声明了两个变量
output1和output2,如果你不想声明也可以,直接就两个类型 - 如果只有一个返回值且不声明返回值变量,那么你可以省略 包括返回值 的括号
- 如果没有返回值,那么就直接省略最后的返回信息
- 如果有返回值, 那么必须在函数的外层添加return语句
我们知道,变量在内存中是存放于一定地址上的,修改变量实际是修改变量地址处的内存。只有add1函数知道x变量所在的地址,才能修改x变量的值。所以我们需要将x所在地址&x传入函数,并将函数的参数的类型由int改为*int,即改为指针类型,才能在函数中修改x变量的值。此时参数仍然是按copy传递的,只是copy的是一个指针。
这样,我们就达到了修改x的目的。那么到底传指针有什么好处呢?
- 传指针使得多个函数能操作同一个对象。
- 传指针比较轻量级 (8bytes),只是传内存地址,我们可以用指针传递体积大的结构体。如果用参数值传递的话, 在每次copy上面就会花费相对较多的系统开销(内存和时间)。所以当你要传递大的结构体的时候,用指针是一个明智的选择。
- Go语言中
channel,slice,map这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递指针。(注:若函数需改变slice的长度,则仍需要取地址传递指针)
defer
Go语言中有种不错的设计,即延迟(defer)语句,你可以在函数中添加多个defer语句。当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回。
Panic和Recover
Go没有像Java那样的异常机制,它不能抛出异常,而是使用了panic和recover机制。一定要记住,你应当把它作为最后的手段来使用,也就是说,你的代码中应当没有,或者很少有panic的东西。这是个强大的工具,请明智地使用它。那么,我们应该如何使用它呢?
Panic
是一个内建函数,可以中断原有的控制流程,进入一个
panic状态中。当函数F调用panic,函数F的执行被中断,但是F中的延迟函数会正常执行,然后F返回到调用它的地方。在调用的地方,F的行为就像调用了panic。这一过程继续向上,直到发生panic的goroutine中所有调用的函数返回,此时程序退出。panic可以直接调用panic产生。也可以由运行时错误产生,例如访问越界的数组。
Recover
是一个内建的函数,可以让进入
panic状态的goroutine恢复过来。recover仅在延迟函数中有效。在正常的执行过程中,调用recover会返回nil,并且没有其它任何效果。如果当前的goroutine陷入panic状态,调用recover可以捕获到panic的输入值,并且恢复正常的执行。
main函数和init函数
Go里面有两个保留的函数:init函数(能够应用于所有的package)和main函数(只能应用于package main)。这两个函数在定义时不能有任何的参数和返回值。虽然一个package里面可以写任意多个init函数,但这无论是对于可读性还是以后的可维护性来说,我们都强烈建议用户在一个package中每个文件只写一个init函数。
1.点操作
import(
. "fmt"
)
这个点操作的含义就是这个包导入之后在你调用这个包的函数时,你可以省略前缀的包名
2.别名操作
import(
f "fmt"
)
别名操作顾名思义我们可以把包命名成另一个我们用起来容易记忆的名字
3._操作
import (
"database/sql"
_ "github.com/ziutek/mymysql/godrv"
)
_操作其实是引入该包,而不直接使用包里面的函数,而是调用了该包里面的init函数。