Go安装及配置环境
下载最新的 zip 文件: go#.#.#.windows-amd64.zip ,这里的 #.#.# 是 Go 的最新版本号。
解压缩 go#.#.#.windows-amd64.zip 文件到你选择的位置。比如D:\Go
在系统中设置两个环境变量:GOROOT和GOPATH
GOPATH 指向的是你的工作目录。
GOROOT 指向的是go的源文件的存放目录,也就是D:\GO,添加 %GOROOT%\bin 到系统的 PATH 环境变量。
测试是否配置成功:
然后打开一个 cmd 命令终端,输入 go version
。 你会得到一个 go version go1.3.3 windows/amd64 的输出,即表示 Go 安装完成。
运行一个go程序
package main
func main() {
println("hello world!") //使用内置函数 println 打印出字符串。
}
将上述内容保存为一个xxx.go文件,然后打开一个 shell 或者终端,进入到文件保存的目录内,通过敲入以下命令来运行程序:
go run xxx.go
如果 golang 环境配置正确,将打印出hello world!。
Go 是一门编译型语言,直接运行go run
命令已经包含了编译和运行。它使用一个临时目录来构建程序,执行完后清理掉临时目录。可以执行以下命令来查看临时文件的位置:
go run --work xxx.go
可以使用go build xxx.go
命令来编译代码,这将产生一个可执行文件 xxx.exe
。
在开发中,既可以使用 go run
也可以使用 go build
。但正式部署的时候,应该部署 go build
产生的二进制文件,然后执行它。
入口函数main
在 go 中,程序入口必须是 main
函数,并且在 main
包内,也就是文件第一行的package main
。
import导入包
import
关键字被用于去声明文件中代码要使用的包。
在 Go 中,关于导包是很严格的。如果你导入了一个包却没有使用将会导致编译不通过。
Go 的标准库已经有了很好的文档。可以访问 golang.org/pkg/fmt/#Println
去看更多关于 PrintLn
函数的信息。
也可以在本地获取文档:
godoc -http=:6060
然后浏览器中访问 http://localhost:6060
变量及声明
方法一:使用var
下面是 Go 中声明变量和赋值最明确的方法,但也是最冗长的方法:
package main
import (
"fmt"
)
func main() {
var power int //定义了一个 int 类型的变量 power
power = 9000
//以上两行可以合并为
//var power int = 9000
fmt.Printf("It's over %d\n", power)
}
方法二:使用:=
Go 提供了一个方便的短变量声明运算符 :=
,它可以自动推断变量类型,但是这种声明运算符只能用于局部变量,不可用于全局变量:
power := 9000
注意:=
表示的是声明并赋值,所以在相同作用域下,相同的变量不能被声明两次
此外, go 支持多个变量同时赋值(使用 =
或者 :=
):
func main() {
name, power := "Goku", 9000
fmt.Printf("%s's power is over %d\n", name, power)
}
多个变量赋值的时候,只要其中有一个变量是新的,就可以使用:=
。例如:
func main() {
power := 1000
fmt.Printf("default power is %d\n", power)
name, power := "Goku", 9000
fmt.Printf("%s's power is over %d\n", name, power)
}
注意:Go 不允许在程序中有声明了但未使用的变量。例如:
func main() {
name, power := "Goku", 1000
fmt.Printf("default power is %d\n", power)
}
不能通过编译,因为 name
是一个被声明但是未被使用的变量,就像 import 的包未被使用时,也将会导致编译失败。
函数声明
函数声明格式:
func 函数名([参数名,参数类型]…) ([返回值类型]…){
}
注意在go中是先写参数名,再写参数类型的。。
以下三个函数:一个没有返回值,一个有一个int类型的返回值,一个有两个返回值(int型和bool型)。
func log(message string) {
}
func add(a int, b int) int {
}
//或者可以写成
//func add(a, b int) int {
//}
func power(name string) (int, bool) {
}
我们可以像这样使用最后一个:
value, exists := power("goku") //用两个变量value和exists来接收power函数的两个返回值
if exists == false {
// 处理错误情况
}
有时候,我们仅仅只需要关注其中一个返回值。就可以将其他的返回值赋值给空白符_
:
_, exists := power("goku")
if exists == false {
// handle this error case
}
_
,空白标识符实际上返回值并没有赋值。所以可以一遍又一遍地使用 _
而不用管它的类型。
slice切片
slice创建和初始化
切片是数组的一个引用,因此切片是引用类型。但自身是结构体,值拷贝传递。
var 或者 :=
var slice1 []int = []int{
0,1,2,3,4,5}
var slice2 = []int{
0,1,2,3,4,5}
slice3 := []int{
0,1,2,3,4,5} //局部
make
var slice []type = make([]type, len)
slice := make([]type, len)
slice := make([]type, len, cap)
使用 make 动态创建slice,避免了数组必须用常量做长度的麻烦。还可用指针直接访问底层数组,退化成普通数组操作。
从数组切片
arr := [5]int{
1, 2, 3, 4, 5} //这里是[...],所以是个数组
slice := []int{
} //这里是[],没有指明长度,所以是个切片
// 切片操作前包后不包
slice = arr[1:4]
fmt.Println(slice)
package main
import "fmt"
func main() {
slice := []int{
0,1,2,3,4,5}
//a[x:y:z] 切片内容 [x:y] len:y-x cap:z-x
//不写z,默认是len
s1 := slice[1:2] //x=1,y=2,z=6 len=1 cap=5
fmt.Println(s1)
fmt.Println("cap of s1", cap(s1))
s2 := slice[:3:4] //x=0,y=3,z=4 len=3 cap=4
fmt.Println(s2)
fmt.Println("cap of s2", cap(s2))
s3 := slice[1:3:5] //x=1,y=3,z=5 len=2 cap=4
fmt.Println(s3)
fmt.Println("cap of s3", cap(s3))
}
切片的内存布局
读写操作实际目标是底层数组,只需注意索引号的差别。
append内置函数
append :向 slice 尾部添加数据,返回新的 slice 对象。
package main
import (
"fmt"
)
func main() {
s1 := make([]int, 1, 5)
fmt.Printf("%p\n", &s1)
s2 := append(s1,