Go基础
安装
然后设置代理
go env -w GO111MODULE=on
go env -w GOPROXY=https://proxy.golang.com.cn,direct
用户家目录会自动生成一个go文件夹,含有bin、src、pkg文件夹,其中src文件夹在GO111MODULE=“on"时没用,其他两个用于存放导入的外部包源码和二进制文件
When using modules, GOPATH is no longer used for resolving imports. However, it is still used to store downloaded source code (in GOPATH/pkg/mod) and compiled commands (in GOPATH/bin).
代码结构
code -> package -> module
包是在同一目录中的源文件集合,模块是一起发布的相关Go包的集合,存储库包含一个或多个模块(通常只有一个)
编写可执行的应用程序必须含有main包和main函数,编写可被导入的第三方包则不需要
包内的init函数最先运行
类型
推荐:https://tour.go-zh.org/list
bool
string
// int, uint 和 uintptr 在 32 位系统上通常为 32 位,在 64 位系统上则为 64 位
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8 的别名
rune // int32 的别名 表示一个 Unicode 码点
float32 float64
complex64 complex128
不同类型赋值均需显示转换
变量声明
var a int = 1
a := 2 //只能在函数内部使用
// 常量不能用 := 语法声明
const b = 3
语句
Go只有一种循环结构:for循环
for i := 1; i < 10; i++ {
sum += i
}
// 等价为c++中的while
for sum < 10 {
sum += 1
}
// 无限循环
for {
}
if语句
if i < 1 {
}
// 可以在条件前加一个简单语句
if i := m; i < 10 {
}
switch:Go只运行选定的 case,而非之后所有的 case。实际上,Go 自动提供了在这些语言中每个 case 后面所需的 break 语句。 除非以 fallthrough 语句结束,否则分支会自动终止。 Go 的另一点重要的不同在于 switch 的 case 无需为常量,且取值不必为整数。
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
fmt.Printf("%s.\n", os)
}
// 没有条件的 switch 同 switch true 一样,这种形式能将一长串 if-then-else 写得更加清晰
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
如果有一个指向结构体的指针 p,那么可以通过 (*p).X 来访问其字段 X。不过这么写太啰嗦了,所以语言也允许我们使用隐式间接引用,直接写 p.X 就可以
结构体定义:
var a = Vertex{X:1, Y:2}
不需要如下形式
var a Vertex = Vertex{X:1, Y:2}
方法
func关键字后括号中的为方法接收者类型,当方法接收者为指针类型时,方法可改变对象的值
如var p *Vertex指针类型调用方法时,对值类型实现的Abs()方法可直接通过p.Abs()进行调用,编译器会自动转为(*p).Abs()
如var v Vertex值类型调用方法时,对指针类型实现的Scale()方法可直接通过v.Scale()进行调用,编译器会自动转为(&v).Scale()
type Vertex struct {
X, Y float64
}
// 为Vertex类型实现了Abs()方法
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
// 为*Vertex类型实现了Scale()方法
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
接口
值类型与指针类型属于不同的类型
type Abser interface {
Abs() float64
}
// 如下 Vertex类型实现了Abser接口,但*Vertex未实现,即*Vertex类型不能赋值给Abser,反之同理
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
// 空接口:指定了0个方法的接口
// 空接口可保存任何类型的值
var i interface{}
类型断言:提供了访问接口值的底层具体值的方式。
t, ok := i.(T)
如 a, ok := i.(int64)
类型选择:
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)
}
goroutine channel
go f(x, y, z) // 会启动一个新的 Go 协程并执行
f(x, y, z) // f, x, y 和 z 的求值发生在当前的 Go 协程中,而 f 的执行发生在新的 Go 协程中
ch := make(chan int, 100) // 信道在使用前必须创建
ch <- v // 将 v 发送至 ch。
v := <-ch // 从 ch 接收值并赋予 v。
发送者可通过 close 关闭一个channel来表示没有需要发送的值了。接收者可以通过为接收表达式分配第二个参数来测试channel是否被关闭:若没有值可以接收且信道已被关闭,那么在执行完v, ok := <-ch之后 ok 会被设置为 false。
循环for i := range ch会不断从信道接收值,直到它被关闭。只有发送者才能关闭信道,而接收者不能
select
select 会阻塞到某个分支可以继续执行为止,这时就会执行该分支。当多个分支都准备好时会随机选择一个执行
当 select 中的其它分支都没有准备好时,default 分支就会执行
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
default:
//
}