Golang 学习笔记

# 特点

# 语言特征

  • 类C语言
  • 强类型
  • 强制语法

# 语言优点

  • 语法简练
  • 标准库较多
  • 部署简单
  • 可自动推导类型
  • 拥有GC
  • Goroutines
  • Channels
  • Defer

# 语言缺点

  • 语法怪异
  • 第三方库较少
  • 错误处理简单
  • 缺少枚举

# 语法

# 数据类型

  • 布尔型:bool
  • 有符整型:int, int8(byte), int16, int32(rune), int64
  • 无符整型:uint, uint8, uint16, uint32, uint64, uintptr
  • 浮点型:float32, float64
  • 复数型:complex64, complex128
  • 字符串型:string

# 运算符

类型运算符结合性
逗号运算符,>>
赋值运算符=、+=、-=、*=、/=、 %=、 >=、 <<=、&=、^=、|=<<
逻辑或||>>
逻辑与&&>>
按位或|>>
按位异或^>>
按位与&>>
相等/不等==、!=>>
关系运算符<、<=、>、>=>>
位移运算符<<、>>>>
加法/减法+、->>
乘法/除法/取余*(乘号)、/、%>>
单目运算符!、*(指针)、& 、++、–、+(正号)、-(负号)<<
后缀运算符( )、[ ]、->>>

# 变量声明与赋值

// 普通声明
var a int // a == 0
var a float // a == 0.0
var a bool // a == false
var a string // a == ""
var a *int // a == nil
var a, b int // a == 0, b == 0

// 普通声明并赋值
var a int = 1 // a == 1
var b = 1 // b == 1
var a, b = 1, 2 // a == 1, b == 2

// 推导声明并赋值
a := 1 // a == 1
a, b := 1, 2 // a == 1, b == 2

// 批量声
var (
  a int
  b float
  c struct {
    d bool
  }
) // a == 0, b == 0.0, d == false

// 匿名变量
_, a = 1, 2 // a == 2

# 变量作用域

package main

a := 1 // 全局变量

func main() {
  b := 1 // 局部变量
}

# 常量

const a int = 1 // a == 1
const a = 1 // a == 1
const (
  a = 1 // a == 1
  b = 1.1 // b == 1.1
)
  • 常量类型只为基础类型
  • 常量需要在编译时确定
  • 常量可以用作数组长度
  • 推导声明会产生无类型常量
  • 无类型常量通用于子基础类型

# 类型定义与别名

type Long int32 // Long
type Int32 = int32 // int32

# 注释、关键字和标识符

# 注释

// 单行
/*
多行
*/

# 关键字

  • var, const, type
  • if, else, switch, case, default, fallthrough
  • for, goto
  • break, continue
  • map, range, chan, select, go
  • import, package
  • func, return, defer
  • struct, interface

# 标识符规则

  • 由英文字母、数字、下划线组成
  • 严格区分大小写
  • 不能以数字开头
  • 不能包含空格
  • 不能是关键字
  • 不能是标准库包名
  • 建议使用驼峰命名法
  • 大写开头是Public
  • 小写开头是Private

# 预定义标识符

  • bool
  • int, int8, int16, int32, int64, byte, rune
  • uint, uint8, uint16, uint32, uint64, uintptr
  • float32, float64
  • complex, complex64, complex128
  • string
  • false, true, nil, iota
  • new, make
  • copy, append, delete
  • len, cap
  • close, recover, panic
  • print, println
  • real, imag

# nil

  • nil 没有类型
  • nil 不能比较
  • nil 地址为 0x0
  • nil 为指针、容器、通道、函数、接口的空值
  • nil 所占空间与类型一致

# 逻辑

# if else

if true {
  // codes
}

if true {
  // codes
} else {
  // codes
}

if true {
  // codes
} else if false {
  // codes
} else {
  // codes
}

if b = false; b {
  // codes
}

# switch case

a := 1
switch a {
  case 1:
    // codes
  case 2:
    // codes
  default:
    // codes
}

switch {
  case a > 0:
    // codes
}

switch a {
  case 1:
    // codes
    fallthrough
  case 2:
    // codes
    fallthrough
  default:
    // codes
}

# for

for {
  // codes
}

for true {
  // codes
}

for i := 0; i < 5; i++ {
  // codes
}

i := 0
for ; i < 5; i++ {
  // codes
}

i := 0
for ; ; i++ {
  // codes
}
for key, val := range "123" {
  // codes
}

for key, val := range []int{1, 2, 3} {
  // codes
}

for key, val := range map[int]string{1:"a", 2:"b"} {
  // codes
}

a := make(chan int)
a <- 1
a <- 2
for val := range a {
  // codes
}

# goto

test:
  // codes
goto test

# break / continue

for {
  break
}

for {
  continue
}

# 容器

# 数组

var a [2]int // a == [0, 0]
var b = [3]int{1, 2} // b == [1, 2, 0]
c := [...]int{1, 2, 3} // c == [1, 2, 3]

var d [2][2]int // d == [[0, 0], [0, 0]]
e := [2][2]int{{1}, {1:2}} // e == [[1, 0], [0, 2]]

# 切片

var a []int // a == []
var b = []int{} // b == []
c := []int{1, 2}[0:0] // c == []
d := []int{1, 2}[:] // d == [1, 2]
e := make([]int, 2, 5) // e == [] len(e) == 2 cap(e) == 5

f := append([]int{}, 1) // f == [1]
g := append([]int{}, 1, 2) // g == [1, 2]
h := append([]int{}, []int{1, 2, 3}...) // h == [1, 2, 3]
i := append([]int{0, 1}, []int{2, 3}...) // i == [0, 1, 2, 3]
j := append([]int{0}, append([]int{1}, []int{2}...)...) // j == [0, 1, 2]
k := []int{1, 2, 3}[1:] // k == [2, 3]
l := []int{1, 2, 3}[:2] // l == [1, 2]
m := append([]int{1, 2, 3}[:1], []int{1, 2, 3}[2:]...) // m == [1, 3]

# Map

var a map[int]string // a == {}
b := make(map[int]string , 100) // b == {}
c := map[int]string{1: "a", 2: "b"} // c == {1: "a", 2: "b"}
delete(map[int]string{1: "c", 2: "d"}, 1) // "map" == {2: "d"}

# 函数

# 声明

func a(i int, j int) int { return i + j } // a(1, 2) == 3
b := func(i int, j int) int { return i + j } // b(1, 2) == 3
c := func(i int, j int) int { return i + j }(1, 2) // c == 3
d := func(i ...int) int { return len(i) }(0, 1) // d == 2

# defer

fmt.Println(0)
defer fmt.Println(1)
defer fmt.Println(2)
fmt.Println(3)
// 0
// 3
// 2
// 1

# panic

panic("error")
// panic: error

# recover

defer func() {
  if r := recover(); r != nil {
    fmt.Println(r)
  }
}()
fmt.Println(1)
panic(2)
fmt.Println(3)
// 1
// 2

# 结构体

# 声明

type A struct {
  B int
  C string
}
var a A // a == {0, ""}
b := A{1, "2"} // b == {1, "2"}
c := new(A) // c == &{0, ""}
d := &A{} // d == &{0, ""}
e := &A{1, "2"} // e == &{1, "2"}
a := struct {
  B int
  C string
}{1, "2"} // f == {1, "2"}

# 访问控制

package A
type A struct {
  B int
  b int
}

package B
a := A{}
a.B = 1 // success
a.b = 1 // error

# 嵌入

type A struct {
  B int
  C string
}
type D struct {
  A
  E int
  F string
}
d := D{A{1, "2"}, 3, "4"} // d == {{1, '2'}, 3, '4'}
d.A.b = 2 // d == {{2, '2'}, 3, '4'}
d.b = 3 // d == {{3, '2'}, 3, '4'}

# 成员方法

type A struct {
  b int
}
func (a *A) plus() {
  a.b += 1
}
a := A.A{}
a.plus() // a == {1}

# 接口

# 声明

type A interface {
  b(int) int
}
var a A

# 实现

type A interface {
  set(int)
}
type B interface {
  get() int
}
type C struct {
  D int
}
func (c *C) set(n int) {
  c.D = n
}
func (c *C) get() int {
  return c.D
}

c := new(C) // c == &{}

var a A // a == nil
a = c // a == &{}
a.set(1) // a == &{1}

var b B // b == nil
b = c // b == &{1}
n = b.get() // n == 1

# 空接口

var a interface{} // a == nil
a = 1 // a == 1
a = 0.1 // a == 0.1
b, ok := a.(int) // b == 0, ok = false

# 包

# 导入

import "a" // 单行导入
import ( // 多行导入
  "b" // 绝对路径 "GOPATH/src/"
  "./c" // 相对路径
  E "e" // 别名引用
  . "f" // 省略引用
  _ "g" // 匿名引用
)

# 自定义

- a
-- a.go
package a
type A struct {
  B int
}
func NewA(n int) *A {
  return &A{B: n}
}
func (a *A) SetB(n int) {
  a.B = n
}
func (a *A) GetB() int {
  return a.B
}

- main
-- main.go
package main

import (
  "./a"
)

func main() {
  a := a.NewA(1) // a.B == 1
}

# 多线程

# Goroutine

f := func(n int) {
  n += 1
}
go f(1) // n == 2

go func(n int) {
  n += 1
}(1) // n == 2

# Channel

var a chan int
var b chan<- int
var c <-chan int

d := make(chan int) // 双向
e := make(chan<- int) // 单入向
f := make(<-chan int) // 单出向

g := make(chan int, 0) // 阻塞
h := make(chan int, 100) // 填满前不阻塞

ch <- 1 // 写入
c := <-ch // 读出
d, ok := <-ch // 强制读出
<-ch // 丢弃读出
close(c) // 关闭

# 常用技巧

# 类型转换

int, err := strconv.Atoi("0")
int64, err := strconv.ParseInt("0", 10, 64)
string := strconv.Itoa(0)
string := strconv.FormatInt(0, 10)

# 时间戳

t1 := time.Now().Unix() // 秒级时间戳
t2 := time.Now().UnixNano()/1e6 // 毫秒级时间戳
t3 := time.Now().UnixNano() // 纳秒级时间戳

# 添加代理

$ go env # 查询配置
$ go env -json # 查询配置以Json形式
$ go env -w GO111MODULE=on # 开启
$ go env -w GOPROXY=[url],direct # 设置
$ go env -u GOPROXY # 取消

# 常用镜像

https://goproxy.cn/
https://goproxy.io/
https://mirrors.aliyun.com/goproxy/

# Map中Key值是否存在

var value, ok = demo["key"]

# Base64加密解密

var str = base64.StdEncoding.EncodeToString([]byte(""))
var bytes, err = base64.StdEncoding.DecodeString("")

# 计划

  • *常用命令
  • *字符串
  • *指针
  • *select
  • *类型转换
  • *包管理
  • *泛型
  • 堆栈
  • iota 常量生成器
  • godoc工具
  • 容器的线程安全
  • make和new的区别
  • 函数递归
  • 函数闭包
  • 测试
  • 结构体比较
  • I/O操作
  • 锁(乐观、悲观、互斥、死活)
  • 多核优化
  • 反射注入
  • 文件操作
  • 常用包
  • sync.WaitGroup
  • container/list
  • container/ring

# 参考

版权协议