Golang

数据类型

声明

1
2
var name type = value
name := value // name 未使用过

转换

1
int32(8) // int float 都适用

$\rightarrow string$ 转换

方式一:$fmt.Sprintf()$

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
fmt.Sprintf("%参数", 表达式) 
bool
%t the word true or false

digit
%b base 2
%c the character represented by the corresponding Unicode code point
%d base 10
%o base 8
%O base 8 with 0o prefix
%q a single-quoted character literal safely escaped with Go syntax.
%x base 16, with lower-case letters for a-f
%X base 16, with upper-case letters for A-F
%U Unicode format: U+1234; same as "U+%04X"

float
%b decimalless scientific notation with exponent a power of two,
in the manner of strconv.FormatFloat with the 'b' format,
e.g. -123456p-78
%e scientific notation, e.g. -1.234456e+78
%E scientific notation, e.g. -1.234456E+78
%f decimal point but no exponent, e.g. 123.456
%F synonym for %f
%g %e for large exponents, %f otherwise. Precision is discussed below.
%G %E for large exponents, %F otherwise
%x hexadecimal notation (with decimal power of two exponent), e.g. -0x1.23abcp+20
%X upper-case hexadecimal notation, e.g. -0X1.23ABCP+20

方式二: $strconv$ 包

1
2
strconv.FormatInt(i int64, base int) string
strconv.FormatFloat(f float64, fmt byte, prec int, bitSize int) string

$string \rightarrow$ 转换

1
2
strconv.ParseInt(s string, base int, bitSize int) (i int64, err error)
strconv.ParseFloat(s string, bitSize int) (float64, error)

切片

动态数组,可修改。

$string$ 是切片,不可修改。

IO

Input

1
2
3
4
5
6
7
8
9
10
11
var name string
var age int

fmt.Scan(a ...any) (n int, err error) // 返回读取成功的个数和 err
fmt.Scan(&name, &age) // 需要引用 读取下一个 (换行不影响输入)

Scanf(format string, a ...any) (n int, err error)
fmt.Scanf("%s%d", &name, &age) // 需要引用 不能换行输入 !!!

fmt.Scanln(a ...any) (n int, err error) // 和 Scan 类似,但遇到换行就结束
fmt.Scanln(&name) // 输入 bob 18 -> name = bob

流程控制

switch

1
2
3
4
5
6
7
8
9
switch name {
case "a", "A":
fmt.Println("A")
case "b", "B":
fmt.Println("B")
default:
fmt.Println("Default")
}
// 无需 break, case 内可有多个

函数

init

1
func init() {} // 每个源文件都可以有 init(),在 main 前执行,可用来初始化

defer

遇到 $defer$ 语句时,将该语句放入栈(相关值直接拷贝),在函数返回后从栈顶开始执行。

遇到 $panic$ 仍然会执行,可以用来 $recover$ ,类似 $try-catch$

1
2
file = openfile(...)
defer file.close() // 这样可以直接 close() 下面还可继续用

内置函数

1
2
3
4
5
6
7
8
9
10
append()
len()
copy()
min()
max()
new()
make()
recover()
delete()
...

错误处理

$defer \rightarrow panic \rightarrow recover$

1
2
3
4
5
6
7
8
9
10
func testError() {
defer func() {
err := recover() // 捕获异常
fmt.Println("Error! ", err)
}()
var a int = 10
var b int = 0
var c int = a / b // panic
fmt.Println(c)
}

自定义错误类型

1
2
3
4
5
6
7
8
func testError() {
defer func() {
err := recover()
fmt.Println("Error! ", err)
}()
err := errors.New("something wrong") // New
panic(err) // panic
}

面向对象

封装

1
2
3
4
5
6
7
8
9
type Person struct {
Name string
Age int
}

func (p *Person) Set(name string, age int) {
p.Name = name
p.Age = age
}

继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type Person struct {
Name string
Age int
}

type Student struct {
Person // 匿名字段
major string
}

type Teacher struct {
Person // 匿名字段
teach string
}

接口

$interface$ 可用来实现多态。

接口也可继承,也要全部实现。

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
45
46
47
48
49
50
51
52
53
type Behavior interface { // 必须实现接口内所有函数
Say()
Walk()
}

func (s Student) Say() {
fmt.Println("Student Say")
}

func (s Student) Walk() {
fmt.Println("Student Walk")
}

func (t Teacher) Say() {
fmt.Println("Teacher Say")
}

func (t Teacher) Walk() {
fmt.Println("Teacher Walk")
}

func TestInterface(b Behavior) {
b.Say()
b.Walk()
}

a := Teacher{
Person: Person{
Name: "alice",
Age: 24,
},
teach: "math",
}

b := Student{
Person: Person{
Name: "bob",
Age: 18,
},
major: "math",
}

TestInterface(a)
TestInterface(b)

// 基类实现了,子类可以直接用
func (p Person) Say() {
fmt.Println(p.Name, " Say")
}

func (p Person) Walk() {
fmt.Println(p.Name, " Walk")
}

类型断言

1
2
3
4
5
6
7
8
var i interface{}
i = a
c, ok := i.(Teacher) // 类型断言 .(type), 转换成功 ok 为 true
if ok {
TestInterface(c)
} else {
fmt.Println("failed")
}

文件操作

$os$ 内 $File$ 。

1
2
3
4
func Create(name string) (*File, error)
func Open(name string) (*File, error)
func (f *File) Close() error
func (f *File) Name() string // returns the name of the file as presented to Open.

$sample$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
file, err := os.Open("data.txt")
if err != nil {
fmt.Println("Open file failed")
return
}
defer file.Close()
reader := bufio.NewReader(file)
for {
str, err := reader.ReadString('\n') // 读到换行结束, str 中包含换行 '\n'
if err == io.EOF { // EOF结束
break
}
if err == nil {
fmt.Print(str)
} else {
fmt.Print(err)
}
}

JSON

序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func json.Marshal(v any) ([]byte, error)

// struct
p := Person{
Name: "alice",
Age: 18,
}
data, err := json.Marshal(p)
if err == nil {
fmt.Println(string(data))
} else {
fmt.Println(err)
}

// map
f := make(map[string]int)
f["score"] = 100
f["Age"] = 18
data, err := json.Marshal(f)
if err == nil {
fmt.Println(string(data))
} else {
fmt.Println(err)
}

自定义序列化标签

1
2
3
4
type Person struct {
Name string `json:"name"`
Age int `json:"age"` // 反射机制
}

反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func json.Unmarshal(data []byte, v any) error

// struct
str := "{\"name\":\"alice\",\"age\":18}"
var p Person
err := json.Unmarshal([]byte(str), &p)
if err == nil {
fmt.Println(p.Name, p.Age)
} else {
fmt.Println(err)
}

// map
str := "{\"score\":10,\"age\":18}"
p := make(map[string]int)
err := json.Unmarshal([]byte(str), &p)
if err == nil {
fmt.Println(p)
} else {
fmt.Println(err)
}

协程

go

$go$ 关键字,轻量级线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 每隔一秒执行一次
func TestRoutine() {
for i := 0; i < 10; i++ {
fmt.Printf("SubTask%d\n", i)
time.Sleep(time.Second)
}
}

func main() {
go TestRoutine() // 多线程

for i := 0; i < 10; i++ {
fmt.Printf("MainTask%d\n", i)
time.Sleep(time.Second * 2)
}
}

mutex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var (
fac = make([]int, 200)
lk sync.Mutex // 全局变量锁
)

func TestRace(n int) {
res := 1
for i := 1; i <= n; i++ {
res *= i
lk.Lock() // 加锁
fac[i] = res
lk.Unlock() // 解锁
}
}

channel

协程间通信,本质是队列。

所有协程阻塞会 $dead ; lock$ 。

1
2
3
4
5
6
7
func TestChannel() {
//(必须 make 初始化, 不能超过容量)
var a chan int = make(chan int, 3) // 创建一个容量为 3 的 channel
a <- 10 // 放入 channel
b := <-a // 取出 (为空取出会阻塞)
fmt.Println(b)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func TestChannel() {
allchan := make(chan interface{}, 10)
allchan <- 10
allchan <- "bob"
allchan <- Person{
Name: "alice",
Age: 18,
}
<-allchan
<-allchan
p := <-allchan
fmt.Println(p)
p = p.(Person) // 类型断言
fmt.Println(p)
}

$close$

1
2
func close(c chan<- Type)
// 关闭后不能放入新数据,但是仍然可以读取数据

遍历 $channel$

1
2
3
4
close(allchan) // 要先关闭,未关闭会阻塞
for v := range allchan {
fmt.Println(v)
}

协程间通信

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
func writeData(ci chan int) {
fmt.Println("start write")
for i := 0; i < 50; i++ {
ci <- i
fmt.Println("write data", i)
}
close(ci)
fmt.Println("end write")
}

func readData(ci chan int, cb chan bool) {
fmt.Println("start read")
for {
v, ok := <-ci // 读不了会阻塞,然后等待 write 写入, close 后 ok != nil
if !ok {
break
}
fmt.Println("read data", v)
}
close(cb)
fmt.Println("end read")
}

func main() {
ci := make(chan int, 10) // 容量小于数据量,管道放满后, 阻塞等待读取
cb := make(chan bool, 1)

go writeData(ci)
go readData(ci, cb)

for {
_, ok := <-cb // 等待前面协程运行完
if !ok {
break
}
}
}

Reflect

1
2
3
func reflect.TypeOf(i any) reflect.Type // 获取类型(struct 含包名)
func reflect.ValueOf(i any) reflect.Value // 获取值
func (reflect.Type) Kind() reflect.Kind // 返回 int string struct ... 等类型

net

Dial

1
func net.Dial(network string, address string) (net.Conn, error)
1
2
3
4
5
connect, err := net.Dial("tcp", "127.0.0.1:8080") // 发送
if err != nil {
fmt.Println("Dial error: ", err)
return
}

Write

1
func (net.Conn) Write(b []byte) (n int, err error) // 向连接中写入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
reader := bufio.NewReader(os.Stdin)

for {
line, err := reader.ReadString('\n')
if err != nil {
fmt.Println("ReadString error: ", err)
return
}

n, err := connect.Write([]byte(line))
if err != nil {
fmt.Println("connect error: ", err)
return
}
fmt.Printf("send %d bytes data\n", n)
}

Listen

1
func net.Listen(network string, address string) (net.Listener, error)
1
2
3
4
5
6
listen, err := net.Listen("tcp", "0.0.0.0:8080")
if err != nil {
fmt.Println("listen err:", err)
return
}
defer listen.Close()

Accept

1
func (net.Listener) Accept() (net.Conn, error) // 等待 Dial 会产生阻塞
1
2
3
4
5
6
7
8
9
10
for {
fmt.Println("listening...")
connect, err := listen.Accept()
if err != nil {
fmt.Println("listen accept err:", err)
} else {
fmt.Println("accept suceessfully:", connect.RemoteAddr()) // 获取 Dial Addr
}
go process(connect)
}

Read

1
func (net.Conn) Read(b []byte) (n int, err error) // 从连接中读取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func process(connect net.Conn) {
defer connect.Close()
for {
buf := make([]byte, 1024)
n, err := connect.Read(buf)
if err != nil {
fmt.Println("connect read err:", err)
return
} else {
fmt.Printf("read %d bytes data", n)
fmt.Println(buf[:n])
}
}
}

http

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func test(writer http.ResponseWriter, request *http.Request) {
_, err := fmt.Fprintln(writer, "Test http") // 向 writer 写入 data
if err != nil {
fmt.Println("send info error:", err)
}
}

func main() {
http.HandleFunc("/test", test) // http 处理 test
err := http.ListenAndServe(":9090", nil) // 监听并服务 Addr
if err != nil {
fmt.Println("http serve failed:", err)
return
}
}

std

sort

1
2
3
4
5
type Interface interface {
Len() int
Less(i, j int) bool // i, j are indices of sequence elements
Swap(i, j int)
}

Heap

1
2
3
4
5
type Interface interface {
sort.Interface
Push(x any) // add x as element Len()
Pop() any // remove and return element Len() - 1.
}
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
type Item struct {
value int
priority int
}

type PriorityQueue []Item

func (p PriorityQueue) Len() int {
return len(p)
}

func (p PriorityQueue) Swap(i int, j int) {
p[i], p[j] = p[j], p[i]
}

func (p PriorityQueue) Less(i int, j int) bool {
return p[i].priority < p[j].priority
}

func (p *PriorityQueue) Push(x any) {
*p = append(*p, x.(Item))
}

func (p *PriorityQueue) Pop() any {
old := *p
n := len(old)
x := old[n-1]
*p = old[0:n-1]
return x
}

heap.Init(&que)
heap.Push(&que, Item{value: k, priority: 0})
u := heap.Pop(&que).(Item).value