本文所参考的资料包含
Packages, variables and functions
包
fmt表示format的缩写,其中包含了格式化输入输出相关的函数在函数中,如果连续的变量均为同类型,那么可以只定义最后一个变量的类型
What is the difference between := and = in Go?
:=前者将会包含有变量创建的部分,如果左边的变量已经存在,那么直接赋值,否则先创建再赋值=只能完成赋值部分,不包含变量的创建部分同时,
var单独完成变量的创建任务在package scope中,每条语句必须由关键字开头,如
var,func等,也就是说,在这里无法使用short variable declarationGo中的基本类型包括
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32
// represents a Unicode code point
float32 float64
complex64 complex128每一个变量在被声明之后,默认为
zero value,并且不同类型的zero value不同0for numeric types,falsefor the boolean type, and""(the empty string) for strings.
Go是强类型语言,不支持隐式类型转换
Flow control statement: for, if, else, switch and defer
- for loop
- 不同于C, Java中的for循环,此处不需要添加括号
- Go中只存在这一种循环结构
- 后面必须添加
{}对循环语句进行包围,不可以省略
- defer 关键字,通过压栈的方法将相关语句顺序压入栈中,当同级的语句执行完毕之后,按照栈顺序执行defer 的语句
More types: structs, slices, and maps
slicing是一种数据结构,并且每次切片,不是创建了一个新的变量,只是对原有数组的遍历方式发生了改变
同时,可以对slicing literal进行多次切片,每次切片都是对最原始的数组的切片
len(s)获得切片的当前长度cap(s)获得切片的最大长度空切片的
zero value是nil这里特别区分一下len方法以及cap方法
前者表示当前切片对应的元素个数,仅仅与slicing时给定的上边界与下边界有关
后者更偏向于描述了原数组的信息,表示根据当前的切片起点,遍历到原数组的最后一个元素,在切片数组中的下标
Methods and interfaces
Go中不含有类,但是可以针对结构体定义方法
语法中,只需要在func 以及 方法名之间,指定
receiver argumenta method is just a function with a receiver argument.关于
receiver存在两种类型,分别是指针类型以及值类型,很明显,前者可以直接对传入的参数进行修改,而后者不可以With a value receiver, the
Scalemethod operates on a copy of the originalVertexvalue. (This is the same behavior as for any other function argument.) TheScalemethod must have a pointer receiver to change theVertexvalue declared in themainfunction.对于
receiver类型为指针的方法,通过非指针类型对象调用方法是可以的,Go将会自动将v.Scale(10)转化为&v.Scale(10);但是对于接受参数类型为指针的函数而言,必须传入指定类型的变量。对于
receiver为值类型的方法,每次调用会有一次copy,将当前结构体中的数据copy入一个新建的结构体对象,之后在该对象上调用方法,因此如果多次使用值传递的方法,那么程序的性能不会很好接口定义了一些通用的方法
在Go中,可以定义接口类型的变量,该变量可以指向任何实现了接口中定义的全有方法的结构体
需要注意的是,由于方法的
receiver含有值传递、指针传递两种,因此如果结构体中的方法只定义了指针类型的,那么对接口进行赋值时,也只能赋值指针类型的结构体通过assertion方法,可以将接口中存储的对象提取出来
注意assertion方法有两个返回值,第一个用于存储对应变量,第二个返回是否成功
eg.
f, ok := i.(float64)一个空接口可以用来表示任意类型的结构体或者自带类型的变量
通过
type switches可以方便地判断接口变量中存储的变量类型,并且根据不同的情况定义不同的行为1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package main
import "fmt"
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Twice %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
func main() {
do(21)
do("hello")
do(true)
}1
2
3Twice 21 is 42
"hello" is 5 bytes long
I don't know about type bool!特殊接口 —
Stringer1
2
3type Stringer interface {
String() string
}该接口类似于Python中的
__str__(self)方法,在直接print变量的时候,将会执行该方法,便于进行调试特殊接口 —
error1
2
3type error interface {
Error() string
}每次函数调用,尽力那个返回两个值,第一个为正确执行返回的值,第二个为程序的执行结果是否合法
特殊接口 —
io.Reader,其中包含有一个方法func (T) Read(b []byte) (n int, err error)Readpopulates the given byte slice with data and returns the number of bytes populated and an error value. It returns anio.EOFerror when the stream ends.可以认为这是一个输入流,传入字节类型的数组,方法返回之后,n表示其中已经被填写的字节数
Concurrency
通过关键字
go来开启协程特性 —
select通过该关键字,可以很轻松地实现,多个协程在执行完毕之后,才可以执行的协程,定义这样的拓扑关系;在多个同级别协程中,随机地选择一个可以执行的协程 eg.
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
28package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}给定一棵二叉树,编写一个遍历其中的所有结点,并且将结点信息输入通道的函数
注意 这里在启动协程的时候,妥善处理了发送者主动关闭通道的行为
只有这样,后面在取元素的时候,第二个标志位
ok才有效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
45package main
import "golang.org/x/tour/tree"
import "fmt"
/*
type Tree struct {
Left *Tree
Value int
Right *Tree
}
*/
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
return
}
ch <- t.Value
if t.Left != nil {
Walk(t.Left, ch)
}
if t.Right != nil {
Walk(t.Right, ch)
}
}
func main() {
ch := make(chan int)
t := tree.New(1)
go func() {
Walk(t, ch)
close(ch)
}()
for {
val, ok := <- ch
if ok == false {
break
} else {
fmt.Println(val)
}
}
}
How to write Go code
Go文件的存储主要分为两个部分,分别是
bin文件夹用于存储编译好的可执行文件,在配置好环境变量之后,如果存在这样的一个可执行文件
bin/hello那么在命令行中只需要键入
hello即可运行该文件src文件夹源代码文件,主要包含有三部分: 包文件(package source)、命令文件(command source)、测试文件
test source
通过
go install命令进行编译,生成可执行文件到bin文件夹需要注意的是,存在所谓的
base path,也就是说,在install的时候,要么从src文件夹中执行该命令;要么直接进入最底层的源代码文件夹,直接go installbase path也适用于引用其他包对于每一个源代码文件,在名称后面加上
xx_test.go,并且在其中编写测试用例,就可以完成测试功能执行命令为
go test,使用方法同go install