Go Basic Notes
CLI
Installation
sudo apt install golang
echo "export GOPATH=$HOME/gopath"
echo "export PATH=$PATH:$GOPATH/bin"
go env
Basic Command
go version
go run main.go
go fmt /path/to/test
- go 的大部分工具的作用基本单位为 package(directories)
Build
# generate library
go build path/to/libpack
go install path/to/libpack
# generate binary
go install path/to/mainpack
Test
# path/to/pack/demo.go
# path/to/pack/demo_test.go
go test path/to/pack
Clean
go clean -i path/to/pack
Modules
- Remote packages.
$GOPATH/bin/hello
.
go get github.com/golang/example/hello
Packages
package and import
- for path/to/pack:
package pack
import (
"path/to/pack"
)
- 只有首字母大写的函数才可被成功导出, 首字母小写的函数为文件私有函数
Variable
Type Declaration
- Go 将类型置于变量名后的理由: reads clearly, from left to right
:=
不可用在函数外
// 简写类型/赋值
var i,j int = 1, 2
// 省略类型
var c, python, java = true, false, "no!"
// 省略 var 关键字
javascript, ruby, cpp:= true, false, "no!"
// 声明块
import (
"math/cmplx"
)
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)
Type conversions
var x int = 3
var y uint = uint(x)
z := uint(x)
struct
type Vertex struct {
X int
Y int
}
var (
v1 = Vertex{1, 2}
v2 = Vertex{X: 1} // Y: 0
v3 = Vertex{} // X: 0, Y: 0
vp = &Vertex{1, 2} // *Vertex
)
array
数组的长度是其类型的一部分
var a [2]string
a[0] = "Hello"
a[1] = "Golang"
fmt.Println(a[0], a[1])
fmt.Println(a)
slice
- s[lo:lo] == nil
p := []int{2, 3, 5, 7, 11, 13}
fmt.Println("p[1:4] ==", p[1:4])
fmt.Println("p[:3] ==", p[:3]) // p[0:3] => 0, 1, 2
fmt.Println("p[4:]" ==, p[4:]) // p[4:len(p)-1] => 4, ..., len(p)-2
- make 函数创建 slice
a := make([]int, 5) // len(a) = 5
b := make([]int, 0, 5) // len(b) = 0, cap(b) = 5
b = b[:cap(5)] // len(b) = 5, cap(b) = 5
- len && cap
// just shorten/extend, not drop elements
// change len(p), keep cap(p)
p = p [:0]
p = p[:4]
// drop its elements
// change len(p) and cap(p)
p = p[2:]
- append
append(s, 2, 3, 4)
- range(iterator): 返回 2 个值(index int, element copy(s[index]) T), 在每一次迭代 index+=1
pow := []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for i := range pow {
fmt.Printf("index == %d\n", i)
}
for _, v := range pow {
fmt.Printf("value == %d\n", v)
}
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
}
map
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68433, -74.39967
}
ml := map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967,
},
"Google": {37.42202, -122.08408},
}
delete(m, "Bell Labs")
element, ok_flag := m["Google"]
Flow Control
if
if x < 0 {
return true
}
// scope of v: only in if/else statement
if v := math.Pow(x, n); v < lim {
return v
} else {
fmt.Printf("%g >= %g\n", v, lim)
}
for
for sum < 1000 {
sum += sum
}
// scope of i: only in for statement
for i := 0; i < 10; i++ {
sum += i
}
switch
- switch 中的 case 自动 break(除非使用 fallthrough 语句)
switch time.Saturday {
case today+0:
fmt.Println("Today.")
case today+1:
fmt.Println("Tomorrow.")
case today+2:
fmt.Println("In two days.")
default:
fmt.Println("Too far away.")
}
// scope of os: only in switch statement
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
fmt.Printf("%s", os)
}
// alias for if-else long chain
switch { // switch true
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon!")
default:
fmt.Println("Good evening!")
}
defer
defer 语句会将函数执行延迟至上层函数返回处(函数参数会立刻生成):
执行时机
函数设置返回值后, 即将返回调用函数前(若 defer 函数修改返回变量, 则会造成返回值与预期不一致)
func main() {
defer fmt.Println("!")
defer fmt.Println("world")
fmt.Println("hello")
}
=>
func main() {
fmt.Println("hello")
fmt.Println("world")
fmt.Println("!")
}
实质
return_value
= xxx -> invoke defer functions(stack) -> return void
func f() (result int) {
defer func() {
result++
}()
return 0
}
=>
func f() (result int) {
result = 0
func() {
result++
}()
return
}
应用场景
- 资源回收
mu.Lock()
defer mu.Unlock()
- panic 异常的捕获
func f() {
defer func() {
if r:= recover(); r!= nil {
fmt.Println("Recovered in f", r)
}
}()
fmt.Println("Calling g.")
g()
fmt.Println("Returned normally from g.")
}
func g() {
panic("ERROR")
}
- 保证语句(在发生异常的情况下)始终会被执行
- 有意修改返回值
Function
Parameters and Return Value
- 简写参数类型
- 多值返回函数
- 命名返回值(注释文档)
func swap(x, y string) (string, string) {
return y, x
}
func swap_(x, y string) (x_, y_ string) {
x_, y_ = y, x
return
}
func main() {
a, b := swap("hello", "golang")
a_, b_ := swap_("hello", "golang")
fmt.Println(a, b)
fmt.Println(a_, b_)
}
Methods
- Go 中没有 class, 但可以在 struct/同一个包内的 type 上(receiver)定义方法
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())
}
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
} else {
return float64(f)
}
}
func main() {
f := MyFloat(-math.Sqrt2)
fmt.Println(f.Abs())
Receiver
- pointer receiver: 可以改变原值(call by reference)
- value receive: 不可以改变原值(call by value)
- 调用 methods 时, 可以不考虑 v 是 value/pointer, go 会自动处理
func (v *Vertex) changeV() {
v.X += 1
v.Y += 1
}
v.changeV() => (&v).changeV()
func (v Vertex) Abs() {
return abs(v)
}
(&v).Abs() => v.Abs()
- Best Practice: 在同一个类型上定义的所有方法最好统一 receiver 类型(全部 value receivers 或 全部 pointer receivers)
Interface
值
(value, type)
var i I
var t *T
i = t // => (nil, *T)
var i I // => (nil, nil)
Type Assertions
- 单返回值: 断言失败时产生 panic
- 双返回值: 断言失败时不产生 panic
// create empty interface, ("hello", string)
var i interface{} = "hello"
s := i.(string)
s, ok := i.(string) // => true
f, ok := i.(float64)// => false(no panic)
f := i.(float64) // => false with panic
- type switches
switch v := i.(type) {
case int;
fmt.Println("Int.")
case string:
fmt.Println("String.")
default:
fmt.Printf("Other type.")
}
Concurrent
goroutine
go f(x, y, z) // => execute in a new goroutine with share memory
channels
- typed conduit(类型管道)
- block execution
var c chan int = make(chan int)
c <- sum // send sum to channel c
v := <-c // receive from channel c, assign value to v
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s/2):], c)
x, y = <-c, <-c
fmt.Println(x, y, x+y)
}
select
- select(当所有情况都不满足时)可被阻塞
for {
select {
case c <- x:
x, y = y, x+y
case <- quit:
fmt.Println("quit")
return
}
}
Worker Pools
package main
import "fmt"
import "time"
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Println("worker", id, "processing job", j)
time.Sleep(time.Second)
results <- j * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
for j := 1; j <= 9; j++ {
jobs <- j
}
close(jobs)
for a := 1; a <= 9; a++ {
<-results
}
}