8小时转职Golang工程师笔记

基本语法

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main // main包,程序入口包
/*
导包的两种方式
*/
//import "fmt"
//import "time"
import (
"fmt"
"time"
)

// main 方法 程序入口函数
func main() {
fmt.Println("hello Go!")

time.Sleep(1 * time.Second)
}

变量声明

变量

声明全局变量可以使用1,2,3
:= 只能在函数体内部使用

1
2
3
4
5
6
7
8
9
10
11
// 第一种 声明变量,不给初始值, 则默认值 0
var a int

// 第二种 声明变量,并赋值一个初始值
var b int = 100

// 第三种 省略数据类型,自动推导
var c = 200

// 第四种 省去var,自动匹配
e := 100

多变量声明

1
2
3
4
5
6
var xx, yy int = 100, 200

var (
vv int = 200
jj bool = true
)

打印输出数据类型

1
fmt.Printf("type of g = %T\n", g)

常量和iota

常量

使用const声明常量
常量声明后不可被修改

1
const name = "miku"

iota

iota计数器,初始值为0,每行累加1
只能配合 const() 一起使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// const 定义枚举类型
const (
BEIJING = iota // 0
SHANGHAI // 1
SHENZHEN // 2
)

const (
a, b = iota + 1, iota + 2 // iota = 0
c, d // iota = 1
e, f // iota = 2

g, h = iota * 2, iota * 3 // iota = 3
i, k // iota = 4
)

函数

多返回值

  1. 返回多个返回值,匿名的
1
2
3
4
5
6
func foo2(a string, b int) (int, int) {
fmt.Println("a = ", a)
fmt.Println("b = ", b)

return 100, 200
}
  1. 返回多个返回值,有形参名称的
1
2
3
4
5
6
7
8
func foo3(a string, b int) (r1 int, r2 int) {
fmt.Println("a = ", a)
fmt.Println("b = ", b)

// 给有名称的返回值变量赋值
r1, r2 = 100, 200
return
}
  1. 返回多个返回值,返回值类型一样可以省
1
2
3
4
5
6
7
8
9
10
11
12
func foo4(a string, b int) (r1, r2 int) {
fmt.Println("a = ", a)
fmt.Println("b = ", b)

// 注意!!!
fmt.Println("r1 = ", r1) // 0
fmt.Println("r2 = ", r2) // 0

// 给有名称的返回值变量赋值
r1, r2 = 100, 200
return
}

init函数和import导包

init函数

可以用来初始化数据库等配置

这是图片

import匿名和别名导包方式

  1. 匿名(不使用包内的方法,只需要init函数时)
1
2
3
4
5
6
7
8
import (
// 在包前加 _
_ "goclass/5-init/lib1"
)

func main() {
//lib1.Lib1test()
}
  1. 别名
1
2
3
4
5
6
7
import (
mylib1 "goclass/5-init/lib1"
)

func main() {
mylib1.Lib1test()
}

指针

&用来取指针
*用来取值

这是图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func swap(pa *int, pb *int) {
fmt.Println("pa = ", pa)
fmt.Println("*pa = ", *pa)
var swap int
swap = *pa
*pa = *pb
*pb = swap
}

func main() {
a, b := 10, 20
swap(&a, &b)

fmt.Println("a = ", a, "b = ", b)
}

// 输出
pa = 0xc00000a0d8
*pa = 10
a = 20 b = 10

defer

  1. defer的执行顺序,多个defer语句遵循先进后出

这是图片

  1. return比defer先执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func deferfunc() {
fmt.Println("defer func called...")
}

func returnfunc() int {
fmt.Println("return func called...")
return 0
}

func returnAndDefer() int {
defer deferfunc()
return returnfunc()
}

func main() {
returnAndDefer()
}

// 输出
return func called...
defer func called...

slice

声明方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func main() {
slice1 := []int{1, 2, 3}
// 最常用的方式
slice2 := make([]int, 3)
var slice3 []int = make([]int, 3)

fmt.Println(slice1, slice2, slice3)

// 判断一个slice是否为空(nil)
var slice4 []int
if slice4 == nil {
fmt.Println("nil slice4")
} else {
fmt.Println("slice4 not nil")
}
}

追加数据

这是图片

1
2
3
4
5
6
7
8
9
slice1 := make([]int, 3, 4)
// len = 3 cap = 4 slice1 = [0 0 0]
fmt.Println("len = ", len(slice1), "cap = ", cap(slice1), "slice1 = ", slice1)

// 追加数据
slice1 = append(slice1, 1, 2)
// len = 5 cap = 8 slice1 = [0 0 0 1 2]
// cap容量不够时,底层进行双倍扩容
fmt.Println("len = ", len(slice1), "cap = ", cap(slice1), "slice1 = ", slice1)

截取

切片和切片的切片共享同一个底层数组,除非你使用copy()函数进行深拷贝

这是图片

1
2
3
4
s := []int{1, 2, 3}
s1 := s[:] // 1, 2, 3
s2 := s[0:2] // 1, 2
s3 := s[1:] // 2, 3

这是图片

1
2
3
4
5
6
7
8
9
s2, s3 := make([]int, 2), make([]int, 2)
copy(s3, s2)
fmt.Println(s3)
s2[0] = 100
fmt.Println(s3)

// 输出
[0 0]
[0 0]

map

声明方式

第二,三种比较常用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 第一种
var m map[string]string
m = make(map[string]string)
m["one"] = "golang"
m["two"] = "java"
m["three"] = "python"

// 第二种
m1 := make(map[int]string)
m1[1] = "golang"
m1[2] = "java"
m1[3] = "python"

// 第三种
m2 := map[int]string{
1: "golang",
2: "java",
3: "python",
}

使用方式

  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
// 遍历
func printMap(cityMap map[string]string) {
// map是引用转递
for index, value := range cityMap {
fmt.Println("county = ", index)
fmt.Println("city = ", value)
}
}

func main() {
cityMap := make(map[string]string)

// 添加
cityMap["China"] = "Beijing"
cityMap["Japan"] = "Tokyo"
cityMap["USA"] = "NewYork"

// 删除
delete(cityMap, "Japan")

// 修改
cityMap["USA"] = "DC"

// 遍历
printMap(cityMap)
}
  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
func deepCopyMap(oldMap map[string]string) map[string]string {
newMap := make(map[string]string, len(oldMap))

for i, v := range oldMap {
newMap[i] = v
}

return newMap
}

func main() {
cityMap := make(map[string]string)

cityMap["China"] = "Beijing"
cityMap["USA"] = "DC"

newMap := deepCopyMap(cityMap)
fmt.Printf("[old] address: %p, values: %v\n", cityMap, cityMap)
fmt.Printf("[new] address: %p, values: %v\n", newMap, newMap)
}

// 输出
[old] address: 0xc0000880c0, values: map[China:Beijing USA:DC]
[new] address: 0xc0000880f0, values: map[China:Beijing USA:DC]

struct

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type Book struct {
title string
author string
}

func changeAuthor(book *Book) {
book.author = "miku"
}

func main() {
c := Book{
title: "Go Programming Language",
author: "zhang",
}

fmt.Println(c)
changeAuthor(&c)
fmt.Println(c)
}

面向对象

封装

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 Hero struct {
Name string
AD int
Level int
}

func (this *Hero) Show() {
fmt.Println("Name = ", this.Name)
fmt.Println("AD = ", this.AD)
fmt.Println("Level = ", this.Level)
}

func (this *Hero) GetName() string {
return this.Name
}

func (this *Hero) SetName(newName string) {
this.Name = newName
}

func main() {
hero := Hero{
Name: "张三",
AD: 100,
Level: 1,
}

hero.Show()

hero.SetName("李四")

hero.Show()

}

继承

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
type Human struct {
name string
sex string
}

func (this *Human) Eat() {
fmt.Println("Human.Eat()...")
}

func (this *Human) Walk() {
fmt.Println("Human.Walk()...")
}

type SuperMan struct {
Human // 继承Human字段及其方法
level int
}

// 复写父类方法
func (this *SuperMan) Eat() {
fmt.Println("SuperMan.Eat()...")
}

// 创建子类新方法
func (this *SuperMan) Fly() {
fmt.Println("SuperMan.Fly()...")
}

func main() {
h := Human{
name: "zhang3",
sex: "female",
}

h.Eat()
h.Walk()

s := SuperMan{
Human: Human{
name: "li4",
sex: "female",
},
level: 100,
}

s.Eat()
s.Walk()
s.Fly()
}

多态

有一个父类(有接口)
有子类(实现了父类的全部接口方法)
父类类型的变量(指针)指向(引用)子类的具体数据变量

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
type AnimalIF interface {
Sleep()
GetColor() string
GetType() string
}

type Cat struct {
color string
}

func (this *Cat) Sleep() {
fmt.Println("Cat is Sleep")
}

func (this *Cat) GetColor() string {
return this.color
}

func (this *Cat) GetType() string {
return "Cat"
}

type Dog struct {
color string
}

func (this *Dog) Sleep() {
fmt.Println("Cat is Sleep")
}

func (this *Dog) GetColor() string {
return this.color
}

func (this *Dog) GetType() string {
return "Dog"
}

func showAnimal(animal AnimalIF) {
animal.Sleep() // 多态
}

func main() {
var animal AnimalIF // 接口类型父类指针
animal = &Cat{color: "red"}

animal.Sleep()
}

interface

空接口 ‘interface{}’ 代表所有类型的集合。空接口类型的变量可以存储任何类型的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func printArg(arg interface{}) {
fmt.Println(arg)

// 给 interface{} 提供类型断言机制
value, ok := arg.(string)
if ok != true {
fmt.Println("不是string")
} else {
fmt.Println(value)
}
}

func main() {
slice1 := make([]string, 2)
printArg(slice1)
printArg("hello")
}

反射

变量的结构

这是图片

这是图片

reflect包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// TypeOf returns the reflection [Type] that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
func TypeOf(i any) Type {
eface := *(*emptyInterface)(unsafe.Pointer(&i))
// Noescape so this doesn't make i to escape. See the comment
// at Value.typ for why this is safe.
return toType((*abi.Type)(noescape(unsafe.Pointer(eface.typ))))
}

// ValueOf returns a new Value initialized to the concrete value
// stored in the interface i. ValueOf(nil) returns the zero Value.
func ValueOf(i any) Value {
if i == nil {
return Value{}
}
return unpackEface(i)
}

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
import (
"fmt"
"reflect"
)

type User struct {
Id int
Name string
Age int
}

func (this User) Call() {
fmt.Println("user is called ...")
fmt.Printf("%v\n", this)
}

func main() {
user := User{
Id: 1,
Name: "miku",
Age: 23,
}

user.Call()
DoFileAndMethod(user)
}

func DoFileAndMethod(input interface{}) {
// 获取input的type
inputType := reflect.TypeOf(input)
fmt.Println("inputType is :", inputType.Name())

// 获取input的value
inputValue := reflect.ValueOf(input)
fmt.Println("inputValue is :", inputValue)

// 通过type获取里面字段
// 1. 获取interface的reflect.Type,通过Type得到NumFieId,进行遍历
// 2. 得到每个fieId,数据类型
// 3. 通过filed有一个Interface()方法得到 对应的value
for i := 0; i < inputType.NumField(); i++ {
field := inputType.Field(i)
value := inputValue.Field(i).Interface()
fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value)
}

// 通过type获取里面的方法,调用
for i := 0; i < inputType.NumMethod(); i++ {
m := inputType.Method(i)
fmt.Printf("%s: %v\n", m.Name, m.Type)
}
}

结构体标签

定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type resume struct {
Name string `info:"name" doc:"我的名字"`
Sex string `info:"sex"`
}

// 遍历
func findTag(str interface{}) {
t := reflect.TypeOf(str).Elem()

for i := 0; i < t.NumField(); i++ {
tagInfo := t.Field(i).Tag.Get("info")
tagDoc := t.Field(i).Tag.Get("doc")
fmt.Println("info:", tagInfo, "doc: ", tagDoc)
}
}

func main() {
var re resume
findTag(&re)
}

应用

json编码和解码
orm映射关系

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
import (
"encoding/json"
"fmt"
)

type Movie struct {
Title string `json:"title"`
Year int `json:"year"`
Price int `json:"rmb"`
Actor []string `json:"actors"`
}

func main() {
movie := Movie{"喜剧之王", 2000, 10, []string{"周星驰", "张柏芝"}}

// 编码的过程 结构体 ---> json
jsonStr, err := json.Marshal(movie)
if err != nil {
fmt.Println("json marshal err:", err)
return
}

fmt.Printf("jsonStr = %s\n", jsonStr)

// 解码的过程 jsonstr ---> json
movie1 := Movie{}
fmt.Println(movie1)
err1 := json.Unmarshal(jsonStr, &movie1)
if err1 != nil {
fmt.Println("json unmarshal err:", err)
}
fmt.Println(movie1)
}