menu

go

golang 最反直觉的就是 GOPATH http://c.biancheng.net/view/4773.html

幸好有了 go mod

go 不支持范型

在 Go 中,如果一个名字以大写字母开头,那么它就是已导出的。任何“未导出”的名字在该包外均无法访问。

变量需要声明可用 var,也可以用短变量声明 :=(类型推导) 但不能在函数体外使用,也有常量关键字 const

多返回值:函数可以返回多个不同类型的结果。

Go 在不同类型的项之间赋值时需要显式转换。

循环结构:Go 只有一种循环结构:for 循环,类 c 的语法,只不过更灵活 支持 for sum < 1 {}for {}

条件语句:

  • if 无需小括号
  • switch case,只运行一个 case,支持无条件 switch(等同 if-else)

defer 语句会将函数推迟到外层函数返回之后执行。defer 是一个栈

指针 var p *int 取指 p = &i 取值 *p

结构体

type Vertex struct {
    X int
    Y int
}

构造

var (
	v1 = Vertex{1, 2}  // 创建一个 Vertex 类型的结构体
	v2 = Vertex{X: 1}  // Y:0 被隐式地赋予
	v3 = Vertex{}      // X:0 Y:0
	p  = &Vertex{1, 2} // 创建一个 *Vertex 类型的结构体(指针)
)

数组

var a [10]int // 默认取零值
primes := [6]int{2, 3, 5, 7, 11, 13}

切片运算

a[low : high]  //[low,high)

切片文法,切片文法类似于没有长度的数组文法

[]bool{true, true, false}

在进行切片时,你可以利用它的默认行为来忽略上下界。切片下界的默认值为 0,上界则是该切片的长度。 切片的零值是 nil。

可通过 append 函数扩展cap。类似其他语言的 list

for i, v := range pow {
	fmt.Printf("2**%d = %d\n", i, v)
}

map

m = make(map[string]Vertex)

var m = map[string]Vertex{
"Bell Labs": Vertex{
	40.68433, -74.39967,
},
"Google": {  //Vertex 可省略
	37.42202, -122.08408,
}, }

go 的函数就是一个闭包

面向对象

go 没有类。通过对函数添加接收者,让其变为接收者的方法。这样 kotlin 的 extension, ruby 的 open class 都可以实现

func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

方法只是个带接收者参数的函数。看似很讨巧(避免 NPE),不过貌似实例方法多起来,还是很繁琐的。

mutable 方法,需要用到指针接收者

func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

接口类型 是由一组方法签名定义的集合。

type Abser interface { Abs() float64 }

go 的接口实现是隐式的,其实也是方法指定接收者这种设计决定。好像叫做鸭子类型

类型断言

t, ok := i.(T)

类似强制类型转换,若 i 保存了一个 T,那么 t 将会是其底层值,而 ok 为 true。否则,ok 将为 false 而 t 将为 T 类型的零值,程序并不会产生恐慌

类型选择

switch v := i.(type) {
case T:
    // v 的类型为 T
case S:
    // v 的类型为 S
default:
    // 没有匹配,v 与 i 的类型相同
}

异常处理

go 的异常处理很 c

goroutine

go 相当于 coroutine 的 launch {}

channel ch := make(chan int)
ch <- v    // 将 v 发送至信道 ch。
v := <-ch  // 从 ch 接收值并赋予 v

select 会阻塞到某个分支可以继续执行为止,这时就会执行该分支。当多个分支都准备好时会随机选择一个执行。

select {
case i := <-c:
    // 使用 i
default:
    // 从 c 中接收会阻塞时执行
}

Mutex, goroutine 的锁

// Value 返回给定 key 的计数器的当前值。
func (c *SafeCounter) Value(key string) int {
	c.mux.Lock()
	// Lock 之后同一时刻只有一个 goroutine 能访问 c.v
	defer c.mux.Unlock()
	return c.v[key]
}

SUID SGID

suid 只能用于文件

给目录设置 sgid 可以让其他用户在该目录下创建的文件继承该目录的组权限

sudo chmod g+s /usr/local/bin/htg # 🏠加 sgid bit
keyboard_arrow_up