
Go语言基础

新生代 web 开发语言,在网络安全、运维方面也有不错前景
Golang
go 命令
command
go bug
1
usage: go bug
打开默认浏览器并且开始bug report,包含有用的系统信息
go build
- 生成的可执行文件默认是文件夹名而不是包名
用于测试编译,如有必要会编译与之相关联的包
对于普通包:执行go build之后不会产生任何文件,如果需要生成pkg,使用go install
对于main包:执行go build之后会产生可执行文件,如果想要在$GOPATH/bin下生成相应可执行文件,使用go install,或者使用go build -o path/binfile
1
2
3
4# go build 默认编译当前目录下所有go文件,如果想要编译单文件
go build a.go
# 当然我们也可以指定编译输出的文件名
go build -o res.outgo build 会忽略以 . 和 _ 开头的go文件
1
2
3$ls
array_linux.go array_windows.go array_freebsd.go
# 如果我们在linux下执行go build,会选择性的编译以linux后缀的go文件go clean
这个命令一般用来清除当前源码包里面编译生成的文件
go doc
展示包的文档
内置包:go doc bulitin
http包:go doc net/http
1
2
3
4# 查看某一个包里所有函数
go doc fmt
# 查看该函数相应代码
go doc fmt Printfgo env
打印go的环境信息
go fix
更新包使用新的API
go fmt
格式化代码,不过一般用不到,因为集成开发工具里面自带保存自动格式化
go get
动态获取远程代码包,这个命令内部包含两步:下载源码包,执行go install
go list
列出包或模块
go install
这个命令包含两步:生成可执行文件或者.a包,把编译好的结果移到pkg或bin中
go test
自动读取源码目录下名为*_test.go的文件,生成并运行测试用的可执行文件
go 基础
基础
定义变量
1
2
3
4
5var var1, var2, var3 type = val1, val2, val3
// 不指定类型,自动判断
var var1, var2, var3 = val1, val2, val3
// 使用 := 简化
var1 var2 var3 := val1, val2, val31
2// 丢弃第一个值
_, x := 1, 2已声明未使用的变量会在编译期报错
常量
1
2const constVar = val
const PI float32 = 3.1415926内置类型
Boolean
1
2var isTrue bool = false
isFalse := trueint
1
2
3
4
5
6
7
8
9int8 uint8 byte
int16 uint16
int32 uint32 rune
int64 uint64
float32 float64
// 32 + 32, 64 + 64
complex64 complex128string
字符串是不可变的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18var hello string = "hello"
emptyStr := ""
// change string
// 1.use []byte
s := "hello"
c := []byte(s)
c[0] = 'H'
s = string(c)
// 2.use slice
s := "hello"
s = "H" + s[1:]
// + operator
s1, s2 := "hello", " go"
s3 := s1 + s2
// raw string(for multi line string)
r := `hello
golang.`error
1
2
3
4err := errors.New("emit macho dwarf: elf header corrupted")
if err != nil {
...
}
技巧
分组声明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import (
"fmt"
"os"
)
const (
pi = 3.14
i = 100
prefix = "go_"
)
var (
i int
pi float32
prefix string
)iota
1
2
3
4
5
6
7
8const (
x = iota // x = 0
y = iota // y = 1
z // z = 2
w // w = 3
)
// 每遇到一个关键字,iota重置
const v = iota // v = 0go设计的一些规则
- 大写字母开头的变量是可导出的,也就是其它包可以读取的,是公有变量;小写字母开头是不可导出,为私有变量
- 大写字母开头的函数也一样
array slice map
array
1
2
3
4var arr [n]type
arr := [n]type{...}
// 也可省略长度
arr := [...]type{...}1
doubleArr := [m][n]type{..., ...}
slice
1
2
3var slice []type
slice := []byte{'a', 'b', 'c', 'd'}
slice = arr[i:j] // i ~ j-1内置函数
1
2
3
4
5
6
7
8// 获取slice的长度
len(slice)
// 获取slice的最大容量
cap(slice)
// 向slice中添加一个或多个元素,返回相同类型的slice
slice = append(slice, ...)
// 复制slice,并返回复制元素个数
n := copy(destSlice, srcSlice)append会改变slice所引用的数组的内容,从而影响到引用同一数组的其它slice
当slice中没有剩余空间时(cap = len),此时将动态分配新的数组空间
返回的slice数组将指向这个空间,原数组的内容不变
map
1
2var m map[keyType]valType
m := make(map[keyType]valType)map是无序的,只能通过key来获取
map长度是不固定的,和slice一样是引用类型
map的初始化是通过key:val的方式初始化,map内置有判断是否存在key的方法
1
2
3
4
5
6
7
8rating, ok := rate["C"]
if ok {
...
} else {
...
}
// 使用delete删除键值对
delete(rate, "C")如果两个map指向同一个底层,那么一个改变另一个也改变
make new
make用于内建类型(map,slice,channel)的内存分配,返回初始化后的值
new用于各种类型的内存分配,返回指针
零值
1
2
3
4int 0
uint 0x0
bool false
string ""
流程控制和函数
流程控制
if
1
2
3
4
5
6
7
8
9
10
11
12
13if x > 10 {
...
} else {
...
}
if x := func(); x > 10 {
...
} else if ... {
...
} else {
...
}goto
1
2
3Here:
...
goto Herefor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17for i := 0; i < 100; i++ {
...
}
for sum <= 1000 {
...
}
outer: for i := 10; i > 0; i-- {
for j := 1; j < 10; j++ {
...
break outer
}
}
for k, v := range map {
...
}switch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21switch expr {
case expr1:
...
case expr2:
...
default:
...
}
// 匹配成功后自动break,使用fallthrough强制执行后续case代码
switch i {
case 1:
...
case 2:
...
fallthrough
case 3:
...
fallthrough
default:
...
}
函数
多个返回值
1
2
3
4
5
6
7
8
9func returnMultiVal() (int, int, float32) {
return 1, 2, 3.14
}
func returnMultiVal() (a int, b int, pi float32) {
a = 1
b = 2
pi = 3.14
return
}变参
1
2
3
4
5
6func myF(args...int) {
// args is a slice
for _, n := range args {
fmt.Println(n)
}
}传值与传指针
1
2
3
4
5func swap(a *int, b *int) {
t := *a
*a = *b
*b = t
}传指针使得多个函数可以操作同一个对象,传递更轻量化
defer
延迟语句,当函数执行到最后时这些defer语句会逆序执行,最后该函数返回
1
2
3
4
5
6
7
8
9func open() bool {
file.Open("file")
defer file.Close()
...
if notOK {
return false
}
return true
}函数作为值类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30type int2bool func(int) bool
func isOdd(i int) bool {
if i % 2 == 0 {
return false
}
return true
}
func isEven(i int) bool {
if i % 2 == 0 {
return true
}
return false
}
func filter(slice []int, f int2bool) []int {
var res []int
for _, v := range slice {
if f(v) {
res = append(res, v)
}
}
return res
}
func main() {
slice := []int{1, 2, 3, 4, 5, 7}
odd := filter(slice, isOdd)
even := filter(slice, isEven)
}panic和recover
> 应当把panic作为最后的手段来使用 > > > panic是一个内建函数,可以中断原有的控制流程,当在函数中调用panic时,函数的执行被中断,但是函数中的延迟函数正常执行。这一过程会继续向上,直到发生panic的goroutine中所有调用的函数返回。这种错误可以由panic产生,也可以由运行时错误产生。 > > > recover也是内建函数,可以令进入错误的goroutine恢复。recover仅在延迟函数中有效,在正常的执行流程中调用recover会返回nil,没有其它任何效果。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17var user = os.Getenv("USER")
func init() {
if user == "" {
panic("no value for $USER")
}
}
// 检查作为其参数的函数在执行时是否会产生panic
func throwPanic(f func()) (b bool) {
defer func() {
if x := recover(); x != nil {
b = true
}
}()
f()
return
}main函数和init函数
一个package中最好只有一个init函数,自动调用init( )和main( ),不需要你显式调用,package中init( )是可选的,但是package main中必须要有main函数
程序的初始化和执行都起始于main包,如果main包还导入了其它包,那么就会在编译时将他们依次导入。一个包被多个包同时导入,它只会被导入一次。
当一个包被导入时,如果该包还导入了其它包,那么它会先将其它包导入,然后对这些包中的包级常量和变量进行初始化,接着执行init函数。等所有包都加载完毕,开始对main包中的包级常量和变量进行初始化,然后执行main包中的init函数,最后执行main函数
import
go支持加载自己写的模块
1
2
3
4// 相对路径
import "./model" // 当前文件同一目录的model目录,但是不建议
// 绝对路径
import "shorturl/model" // 加载gopath/src/shorturl/model模块. 操作
1
2
3
4
5import (
. "fmt"
)
// usage(not need fmt)
Println(...)别名操作
1
2
3
4
5import (
f "fmt"
)
// usage
f.Println(...)_ 操作
1
2
3
4import (
_ "github.com/ziutek/mysql/godrv"
)
// 只调用里面的init函数
struct
struct
1
2
3
4
5
6
7
8type person struct {
name string // string字段
age int8 // int8字段
}
var p person
p.name, p.age = "alex", 18
p := person{"tom", 20}
p := person{age:20, name:"mars"}匿名字段(只提供类型不提供字段名)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17type Human struct {
name string
age int8
weight int8
}
type Student struct {
Human
stuId string
}
mark := Student{Human{"mark", 25, 120}, "200309"}
// usage
mark.name
mark.age
mark.weight
mark.stuId实现字段的继承,所有内置类型和自定义类型都可以作为匿名字段
oop
method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19type Rect struct {
width, height float64
}
type Circle struct {
radius float64
}
func (r Rect) area() float64 {
return r.width * r.height
}
func (c Circle) area() float64 {
return c.radius * c.radius * math.Pi
}
// usage
r := Rect{12, 2}
c := Circle{10}
r.area()
c.area()exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59package main
import "fmt"
const(
WHITE = iota
BLACK
BLUE
RED
YELLOW
)
type Color byte
type Box struct {
width, height, depth float64
color Color
}
type BoxList []Box //a slice of boxes
func (b Box) Volume() float64 {
return b.width * b.height * b.depth
}
func (b *Box) SetColor(c Color) {
b.color = c
}
func (bl BoxList) BiggestsColor() Color {
v := 0.00
k := Color(WHITE)
for _, b := range bl {
if b.Volume() > v {
v = b.Volume()
k = b.color
}
}
return k
}
func (bl BoxList) PaintItBlack() {
for i, _ := range bl {
bl[i].SetColor(BLACK)
}
}
func (c Color) String() string {
strings := []string {"WHITE", "BLACK", "BLUE", "RED", "YELLOW"}
return strings[c]
}
func main() {
boxes := BoxList {
Box{4, 4, 4, RED},
Box{10, 10, 1, YELLOW},
Box{1, 1, 20, BLACK},
Box{10, 10, 1, BLUE},
Box{10, 30, 1, WHITE},
Box{20, 20, 20, YELLOW},
}
fmt.Printf("We have %d boxes in our set\n", len(boxes))
fmt.Println("The volume of the first one is", boxes[0].Volume(), "cm³")
fmt.Println("The color of the last one is",boxes[len(boxes)-1].color.String())
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
fmt.Println("Let's paint them all black")
boxes.PaintItBlack()
fmt.Println("The color of the second one is", boxes[1].color.String())
fmt.Println("Obviously, now, the biggest one is", boxes.BiggestsColor().String())
}- 指针作为reciver
- method继承
- method重写