Go 语法基础 | 青训营笔记

58 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记

数据类型

string是基础类型

int float32 float64 string bool

变量/常量

  1. 变量有两种声明方法:var:=, 支持类型自动推导(需给出初始值)
var a = 1
var b int = 2
var c // 错误, 没有类型初值,无法推导

d := 1
e := float32(d)
f += "aaa" + "bbb" // 字符串支持直接拼接
  1. 常量,把var替换为const来声明常量
const a = 1
const b string = "ccc"
const c int = 123

分支/循环

  1. if分支:if 后面的bool表达式没有括号,并且必须将后面的语句包含在换行的大括号里。
if 7 % 2 == 0 {
	// stmt here
}

if 8 % 4 == 0 {
	// stmt
} else {
	// stmt
}

// if语句的最后一块是bool即可,之前可以放任何语句,用逗号隔开
if num := 9; num > 0 {
	// stmt
} else if num < 0 {
	// stmt
}
  1. switch分支:case后自动break
a := 2
switch a {
case 1:
	// 
case 2:
	//
default:
	//
}
  1. for循环:go中的for循环可以实现loop,while,for i,for k, v等
// loop
for {
	fmt.Println("loop")
}

// while
i := 1
for i <= 3 {
	i = i + 1
}

// for i
for j := 1; j < 10; j ++ {
	fmt.Println(j)
}

// for k, v?

数组/切片

  1. 数组使用[N]int[N][N]string来声明数组
var a [5]int
a[4] = 100
fmt.Println(a[4], len(a)) // 100 5

b := [5]int{1, 2, 3, 4, 5}
fmt.Println(b) // [1 2 3 4 5]

var c [2][3]int
for i := 0; i < 2; i++ {
	for j := 0; j < 3; j++ {
		c[i][j] = i + j
	}
}
fmt.Println(b) // [[0 1 2] [1 2 3]]
  1. 切片使用make([]int, capacity)来创建,capacity是切片的初始容量,切片可以使用append()扩充容量
a := make([]int, 3)
a[0] = 1
a[1] = 2
a[2] = 3
fmt.Println(a[1], len(a)) // 2 3

// append()由于会扩充容量,即重新分配容量,需要将切片传进去,并赋值会切片
a = append(a, 4) // 插入值
a = append(a, 5, 6) // 插入两个值
fmt.Println(a) // [1 2 3 4 5 6]

b := make([]int, 6)
copy(b, a) // 将a中的值复制给b

切片操作:大体同Python,但不支持负数下标来倒序访问

// 下标2 -> 5 - 1
fmt.Println(b[2:5]) // [3 4 5]
// 下标0 -> 5 - 1
fmt.Println(b[:5]) // [1 2 3 4 5]
// 下标2 -> len() - 1
fmt.Println(b[2:]) // [3 4 5 6]

哈希表

使用make(map[string]int)来创建哈希表,同C++里的unordered_map<string, int>

mp := make(map[string]int)
mp["a"] = 1
mp["b"] = 2
// 或者mp := map[string]int{"a":1, "b":2}
fmt.Println(mp) // map[a:1 b:2]
fmt.Println(len(mp)) // 2
fmt.Println(mp["a"]) // 1
delete(mp, "b") // 删除键

对于无效键,默认返回值的零值

fmt.Println(mp["unset"]) // 0

// 也可以这样来判断
x, ok := mp["unset"] // x == 0, ok == false

范围

range关键字,可以用于快速遍历切片、哈希表等。如果不需要用到某个值,可以用_来忽略

遍历切片

nums := []int{1, 2, 3}
for i, v := range nums {
	fmt.Println("index:", i, "val:", v)
}

for _, v := range nums {
	fmt.Println("val:", v)
}

遍历哈希表

mp := map[int]int{1:1000, 2:2000, 3:3000}
for k, v := range mp {
	fmt.Println("key:", k, "val:", v)
}

for _, v := range mp {
	fmt.Println("val:", v)
}

函数

go中的函数支持返回多个值

func a() int {
	// 返回int
	return 1
}

func b() (x int, ok bool) {
	x = 2 // x和ok已在上面定义
	ok = true
	return x, ok
	// 语法糖:直接return,就可以返回定义的返回值了
}

func main() {
	aa := a()
	bb, ok := b()
	fmt.Println(aa, bb, ok) // 1 2 true
}

指针

函数可以处理传入的变量指针

func addPtr(x *int) {
	*x += 2
}

func main() {
	a := 1
	addPtr(&a)
	fmt.Println(a) // 3
}

结构体

go中没有类,仅有结构体

type node struct {
    a int
    b int
}

func cmpA(n node, x int) bool {
    return n.a == x
}

func mod(n *node, x int) {
    n.a = x // 指针修改结构体的值无需解引用
}

func main() {
    // 定义结构体
    a := node{a: 1, b: 2}
    // b := node{2, 3}
    // c := node{b: 3} // 定义部分值
    // var d node
    // d.a = 1
    // d.b = 2

    fmt.Println(a) // {1 2}
    fmt.Println(cmpA(a, 2)) // false
    mod(&a, 2)
    fmt.Println(cmpA(a, 2)) // true
}

结构体方法就类似类中的成员函数

type node struct {
    a int
    b int
}

func (n node) cmpA(x int) bool {
	return n.a == x
}

func (n *node) mod(x int) {
	n.a = x
}

异常处理

go使用error类型的返回值抛出异常,使用if来处理异常

func (n *node) mod(x int) (err error) {
    if n.a == 0 {
        return errors.New("no a value")
    } else {
        n.a = x
    }
    return
}

func main() {
    a := node{b: 2}
    // exception handler
    if err := a.mod(1); err != nil {
        fmt.Println(err) // nil struct
        return
    }
    fmt.Println(a.a) // never print
}

JSON处理

go中的encoding/json包可以很方便的序列化结构体和反序列化JSON

type node struct {
    Name string
    Age  int `json:"age"` // key Age -> age
}

func (n *node) Serialize() ([]byte, error) {
    buf, err := json.Marshal(n) // 序列化
    if err != nil {
        return nil, err
    }
    return buf, nil
}

func (n *node) Deserialize(buf []byte) error {
    err := json.Unmarshal(buf, &n) // 反序列化
    if err != nil {
        return err
    }
    return nil
}

func main() {
    n := &node{
        Name: "John",
        Age:  30,
    }
    buf, err := n.Serialize()
    if err != nil {
        panic(err)
    }
    // []byte切片,直接打印是数字,需要类型转换
    fmt.Println(string(buf)) // {"Name":"John","age":30}

    var n2 node
    err = n2.Deserialize(buf)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%#v\n", n2) // main.node{Name:"John", Age:30}
}