数据类型
类型转换
数据结构
程序控制
for/break/continue
switch/case/default
fallthrough
select/case/default
函数调用
“面向对象”
进阶语法
goto
select
- 除 default 外,如果只有一个 case 语句评估通过,那么就执行这个case里的语句;
- 除 default 外,如果有多个 case 语句评估通过,那么通过伪随机的方式随机选一个;
- 如果 default 外的 case 语句都没有通过评估,那么执行 default 里的语句;
- 如果没有 default,那么代码块会被阻塞,直到有一个 case 通过评估;否则一直阻塞
itoa
参考 https://studygolang.com/articles/22498
slice 切片
defer
defer 的语句在 return 之后执行
panic
recover
internal package
Type assertions
package main
import "fmt"
func main() {
var i interface{} = "hello"
s := i.(string)
fmt.Println(s)
s, ok := i.(string)
fmt.Println(s, ok)
f, ok := i.(float64)
fmt.Println(f, ok)
f = i.(float64) // panic
fmt.Println(f)
}
channel
Go提供了range
关键字,将其使用在channel上时,会自动等待channel的动作一直到channel被关闭,如下:
ticker := time.NewTicker(time.Minute * 5)
for range ticker.C {
doSomeThing()
}
如下例子,ch 初始化以后,取出的值默认是 false。
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
ch := make(chan bool)
go func() {
defer close(ch)
//具体的任务,这里模拟做的任务需要1秒完成
time.Sleep(time.Second * 1)
}()
select {
case <- ch:
fmt.Println("ch bool", <- ch)
case <- ctx.Done():
fmt.Println("ctx done")
}
// output:
// ch bool false
带缓冲区和不带缓冲区的区
c1 := make(chan int) // 不带缓冲区
c2 := make(chan int, 100) // 带缓冲区
- 非缓冲
channel
,channel
发送和接收动作是同时发生的 - 例如
ch := make(chan int)
,如果没goroutine
读取接收者<-ch
,那么发送者ch<-
就会一直阻塞 - 缓冲
channel
类似一个队列,只有队列满了才可能发送阻塞
特殊注释
go:linkname
//go:linkname 注释标签引导编译器在编译时将当前私有函数链接到指定的目标函数,也可以作用到变量上面
举例:
time.Sleep() 声明在 time 包,但是实现在 runtime 包的 runtime.timeSleep()
>>>>>>>>>> time/sleep.go <<<<<<<<<<<<<<
package time
// Sleep pauses the current goroutine for at least the duration d.
// A negative or zero duration causes Sleep to return immediately.
func Sleep(d Duration)
>>>>>>>> runtime/time.go <<<<<<<<<<<<<
// timeSleep puts the current goroutine to sleep for at least ns nanoseconds.
//go:linkname timeSleep time.Sleep
func timeSleep(ns int64) {
if ns <= 0 {
return
}
gp := getg()
t := gp.timer
if t == nil {
t = new(timer)
gp.timer = t
}
t.f = goroutineReady
t.arg = gp
t.nextwhen = nanotime() + ns
gopark(resetForSleep, unsafe.Pointer(t), waitReasonSleep, traceEvGoSleep, 1)
}
自己实现一遍,文件目录如下:
├── main.go
├── linked
│ ├── linked.s
│ └── linked.go
├── inner
│ └── inner.go
inner/inner.go
package inner
import (
_ "unsafe"
)
//go:linkname assert linked.Assert
func assert(i interface{}) {
value, ok := i.(string)
if ok == false {
println("false", value)
} else {
fmt.Println("true", value)
}
}
linked/linked.go
package linked
import (
_ "inner"
)
func Assert(s string)
main.go
func main() {
linked.Assert("test")
}
// output:
// false
go:noescape
该指令指定下一个有声明但没有主体(意味着实现有可能不是 Go)的函数,不允许编译器对其做逃逸分析。
一般情况下,该指令用于内存分配优化。因为编译器默认会进行逃逸分析,会通过规则判定一个变量是分配到堆上还是栈上。但凡事有意外,一些函数虽然逃逸分析其是存放到堆上。但是对于我们来说,它是特别的。我们就可以使用 go:noescape
指令强制要求编译器将其分配到函数栈上。
named return value
func f() (i int, s string) {
i = 17
s = "abc"
return // same as return i, s
}
https://tour.golang.org/basics/7
https://yourbasic.org/golang/named-return-values-parameters/
数学计算
位移计算
CGo
举例
package rand
/*
#include <stdlib.h>
*/
import "C"
func Random() int {
return int(C.random())
}
func Seed(i int) {
C.srandom(C.uint(i))
}