GOPATH
go命令依赖于GOPATH,但是GOPATH跟JAVA_HOME不一样,GOPATH是一个工作目录,跟go的安装目录没有任何关系,因此系统中可以设置很多个GOPATH。
GOPATH目录是工作目录,约定好有3个子目录:
- src: 存放源码
- pkg:存放编译后生成的文件(.a文件等等)
- bin:编译后生成的可执行文件
Go编译
编译可使用go build或者go install
$ go build hellogo.go
$ ls
hellogo* hellogo.go
当然我们也 可以通过-o选项来指定其他名字:
$ go build -o myfirstgo hellogo.go
$ ls
myfirstgo* hellogo.go
如果我们在go-examples目录下直接执行go build命令,后面不带文件名,我们将得到一个与目录名同名的可执行文件:
$ go build
$ ls
go-examples* hellogo.go
与build命令相比,install命令在编译源码后还会将可执行文件或库文件安装到约定的目录下。
go install编译出的可执行文件以其所在目录名(DIR)命名
go install将可执行文件安装到与src同级别的bin目录下,bin目录由go install自动创建
go install将可执行文件依赖的各种package编译后,放在与src同级别的pkg目录下.
Go依赖
go语言有一个获取远程包的工具就是go get,目前go get支持多数开源社区(例如:github、googlecode、bitbucket、Launchpad),通过这个命令可以获取相应的源码,对应的开源平台采用不同的源码控制工具,例如github采用git、googlecode采用hg,所以要想获取这些源码,必须先安装相应的源码控制工具。
go get github.com/astaxie/beedb
# go get -u 参数可以自动更新包,而且当go get的时候会自动获取该包依赖的其他第三方包
目录结构:
$GOPATH
src
|--github.com
|-astaxie
|-beedb
pkg
|--相应平台
|-github.com
|--astaxie
|beedb.a
go get本质上可以理解为首先第一步是通过源码工具clone代码到src下面,然后执行go install
在代码中如何使用远程包,很简单的就是和使用本地包一样,只要在开头import相应的路径就可以。
Go测试
测试文件是一个特殊的库文件,go test命令能执行包下的测试代码,测试代码需要符合以下几个要求:
- 测试代码文件以*_test.go命名
- 文件中必须包含一个Test或者Benchmark开头、且有一个testing.T或者testing.B类型参数的函数
Go工具
- pprof:解析Go的一些性能概要文件,输出高可读性的信息。性能概要文件包括CPU概要文件、内存概要文件和程序阻塞概要文件。这些概要文件,可以通过包runtime和runtime/pprof的程序来生成。
- trace:解析Go程序踪迹文件,图形化展示。可以得到Go程序运行过程中的内部情况,比如堆大小和使用情况,goroutine的调度情况。踪迹文件可以通过包runtime/trace、net/http/pprof的程序来生成。
Go的几个点
- main包是程序的入口,包内首字母大写的名称是导出的(类似于静态常量)。
- func定义函数,类型在变量名之后,连续几个类型一致,可以只写最后一个变量的类型。
- 函数支持多值返回,返回值支持命名,称之为返回变量,没有参数的 return 语句返回各个返回变量的当前值。
- for 语句的三个组成部分 并不需要用括号括起来,但循环体必须用 { } 括起来。
- if 语句也不要求用 ( ) 将条件括起来,同时, { } 还是必须有的。跟 for 一样, if 语句可以在条件之前执行一个简单语句。
- switch分支会自动终止,不需要break。
- defer 语句会延迟函数的执行直到上层函数返回。如果有多个defer,则按照声明顺序,逆序执行(等同入栈出栈)。
- go有指针 但是不支持指针运算。
- 结构体其实就是一个拥有多个属性的对象,访问结构体的属性可以使用“.”。支持指针直接访问属性。
- 数组的声明方式是 [n]T,其中T是数组元素类型,n是数组长度,数组是定长的。
- 切片是变长的数组,因此定义的时候([n]T)不需要给出n。内置函数func append(s []T, vs ...T) []T,可以给切片末尾添加元素,返回新的切片,原切片不变。
- for 循环的 range 格式可以对 slice 或者 map 进行迭代循环。
- 映射的类型:map[K]V,其中K是key的类型,V是value的类型。只能通过make来创建。map 的文法跟结构体文法相似,不过必须有键名。删除key需要使用内置函数delete(map, key)
- 函数也是值,可以用来传递和返回。支持闭包。
- Go没有类,但是可以在结构体上定义方法。
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := &Vertex{3, 4}
fmt.Println(v.Abs())
}
- 接口类型是由一组方法定义的集合。只要实现了这些接口,就算是该接口类型,不需要显示声明implement。
- Go支持协程, go f(xxx)就是开启一个goroutine执行函数f(xxx)。goroutine 在相同的地址空间中运行,因此访问共享内存必须进行同步。
- channel是有类型的通道,创建的时候需要使用make(chan T),其中T是类型。
默认情况下,在另一端准备好之前,发送和接收都会阻塞。这使得 goroutine 可以在没有明确的锁或竞态变量的情况下进行同步。
ch <- v // 将 v 送入 channel ch。
v := <-ch // 从 ch 接收,并且赋值给 v。
channel 可以是 带缓冲的。为 make 提供第二个参数作为缓冲长度来初始化一个缓冲 channel:
ch := make(chan int, 100)
向带缓冲的 channel 发送数据的时候,只有在缓冲区满的时候才会阻塞。 而当缓冲区为空的时候接收操作会阻塞。
发送者可以 close 一个 channel 来表示再没有值会被发送了。接收者可以通过赋值语句的第二参数来测试 channel 是否被关闭
v, ok := <-ch
- select 语句使得一个 goroutine 在多个通讯操作上等待。select 会阻塞,直到条件分支中的某个可以继续执行,这时就会执行那个条件分支。当多个都准备好的时候,会随机选择一个。
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
当 select 中的其他条件分支都没有准备好的时候,default 分支会被执行。
为了非阻塞的发送或者接收,可使用 default 分支:
select {
case i := <-c:
// 使用 i
default:
// 从 c 读取会阻塞
}
- sync.Mutex 类型及其两个方法:
Lock
Unlock
实现互斥锁。
网友评论