类型和结构体都可以定义方法,可被调用

一 :配置 GOPROXY加速

Linux

# 启用 Go Modules 功能
go env -w GO111MODULE=on
 
# 配置 GOPROXY 环境变量,以下三选一
 
# 1. 七牛 CDN
 
go env -w  GOPROXY=https://goproxy.cn,direct
 
# 2. 阿里云
 
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct
 
# 3. 官方
 
go env -w  GOPROXY=https://goproxy.io,direct
 
# 确认一下:
$ go env | grep GOPROXY
GOPROXY="[https://goproxy.cn](https://goproxy.cn/)"

Win

# 启用 Go Modules 功能
$env:GO111MODULE="on"
 
# 配置 GOPROXY 环境变量,以下三选一
 
# 1. 七牛 CDN
$env:GOPROXY="https://goproxy.cn,direct"
 
# 2. 阿里云
$env:GOPROXY="https://mirrors.aliyun.com/goproxy/,direct"
 
# 3. 官方
$env:GOPROXY="https://goproxy.io,direct"
 
# 确认一下:
$ go env | findstr GOPROXY
GOPROXY="[https://goproxy.cn](https://goproxy.cn/)"

二: 常用包

https://pkg.go.dev/

可以给包别名从而实现避免命名冲突

import fm “fmt”

fmt : C 的 printf 和 scanf 的功能实现格式化的 I/O 包

rand : 伪随机数的生成

strings : 简单的函数来操作 UTF-8 编码的字符串。

time : 提供了测量和显示时间的功能

三 : 入门

导包制

import “”

变量声明 名前 类后

单个 := 局部变量

var variable DataTypes               // 显式
name := "string"                     // 隐式短声明 !!!全局变量不可用 

多个 其他定义的也可使用

// 不同之一
var ( 
    s1 string = "1";
    s2 string = "2";
)

常量 const

// 允许并行赋值
const beef, two, c = "eat", 2, "veg"
const Monday, Tuesday, Wednesday, Thursday, Friday, Saturday = 1, 2, 3, 4, 5, 6
const (
    Monday, Tuesday, Wednesday = 1, 2, 3
    Thursday, Friday, Saturday = 4, 5, 6
)

// 可使用枚举
const (
    Unknown = 0
    Female = 1
    Male = 2
)

类型转换

value_Of_TypeB = typeB(value_Of_TypeA)

外部访问 首字母大写的变量 函数 可被外面的包访问

输入/输出

引入 fmt 包

fml.printf("%v 你好吖", wood) %v是任意匹配数据类型 特有其他基础和C差不多
%#v 可以将空的字符串打印出来 "" 原始的指

var f = fml.Sprintf("%v 你好吖", wood) 
fmt.printf(f) 
// 输入使用
var name string
fmt.Scan(&name)

数据类型与关键词

byte 单字节

rune 8字节

自定义数据类型

type Code int
type Number interface{
    int|uint|int8|int16
}

const (
  SuccessCode    Code = 0
  ValidCode      Code = 7 // 校验失败的错误
  ServiceErrCode Code = 8 // 服务错误
)

func (c Code) GetMsg() string {
  // 可能会有更加响应码返回不同消息内容的要求,我们在这个函数里面去实现即可
  // 可能还会有国际化操作
  return "成功"
}

func main() {
  fmt.Println(SuccessCode.GetMsg())
  var i int
  fmt.Println(int(SuccessCode) == i) // 必须要转成原始类型才能判断
}

自定义类型别名

type Code = int

  1. 不能绑定方法
  2. 打印类型还是原始类型
  3. 和原始类型比较,类型别名不用转换

关键词

_空白识别符 : 任何赋给这个标识符的值都将被抛弃
nil类似于Null 空值
const声明常量
var声明变量
type定义结构体?
lota遇到一个变量会+1 遇到常量guilubg3
break跳出当前的执行

运算符 同C

位移存在 1 << 10 10 >> 1

数组

var arrlist [i]Datatype = [i]Datatype{}

var nameList []Datatype
nameList = append(nameList, "")
nameList = append(nameList, "")

var nameList []string = []string{}
nameList = make([]string, 0) || 
/* 不需要上面初始化 */ 
nameList := make([]string, 0)

make([]Datatype, length, capacity)

切片 slice 可变长度的固定type 数组

S := []int{1,2,3,4,5,6}
s1 := S[:3] // 从前三个取
s2 := S[3:] // 从后三个取

var nameList []string 
nameList = append(nameList, "")
nameList = append(nameList, "")

指针

& 取值符号

  • 解引用 将值指向原地址
func main() {
    s := "good bye"
    var p *string = &s
    *p = "ciao"
    fmt.Printf("Here is the pointer p: %p\n", p) // prints address
    fmt.Printf("Here is the string *p: %s\n", *p) // prints string
    fmt.Printf("Here is the string s: %s\n", s) // prints same string
}

func Expo

结构体指针

type Student struct {
  Name string
  Age  int
}

func SetAge(info Student, age int) {
  info.Age = age
}

func SetAge1(info *Student, age int) {
  info.Age = age
}

func main() {
  s := Student{
    Name: "枫枫",
    Age:  21,
  }
  fmt.Println(s.Age)
  SetAge(s, 18)
  fmt.Println(s.Age)
  SetAge1(&s, 17)
  fmt.Println(s.Age)
}
type Student struct {
  Name string
  Age  int
}

func (s Student) SetAge(age int) {
  s.Age = age
}
func (s *Student) SetAge1(age int) {
  s.Age = age
}

func main() {
  s := Student{
    Name: "枫枫",
    Age:  21,
  }
  s.SetAge(18)
  fmt.Println(s.Age)
  s.SetAge1(18)
  fmt.Println(s.Age)
}

map 映射

    // 初始化
    var aMap = make(map[string]string)
    var aMap = map[string]string{}
    var usrMap map[int]string = map[int]string{
        1: "wood",
        2: "bird",
    }
    fmt.Println(usrMap)
    fmt.Println(usrMap[1])
    fmt.Println(usrMap[2])
    fmt.Printf("%#v\n", usrMap[4])
    valuse , static = userMap[4] 
    // valuse是 map[int]string 这里定义的string
    // static 是bool 判断是否有值 
    delete(usermap, key值)
    --------------------------------
map[1:wood 2:bird]
wood
bird
""

结构体

type People struct {
  Time string
}

func (p People) Info() {
  fmt.Println("people ", p.Time)
}

// Student 定义结构体
type Student struct {
  People
  Name string
  Age  int
}

// PrintInfo 给机构体绑定一个方法
func (s Student) PrintInfo() {
  fmt.Printf("name:%s age:%d\n", s.Name, s.Age)
}

func main() {
  p := People{
    Time: "2023-11-15 14:51",
  }
  s := Student{
    People: p,
    Name:   "枫枫",
    Age:    21,
  }
  s.Name = "枫枫知道" // 修改值
  s.PrintInfo()
  s.Info()                   // 可以调用父结构体的方法
  fmt.Println(s.People.Time) // 调用父结构体的属性
  fmt.Println(s.Time)        // 也可以这样
}

结构体标签

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

func main() {
  s := Student{
    Name: "枫枫",
    Age:  21,
  }
  byteData, _ := json.Marshal(s)
  fmt.Println(string(byteData))
}

接口

type SingInterface interface {
    Sing()
    GetName() string
}

type Chicken struct {
    Name string
}

func (c Chicken) Sing() {
    fmt.Println(c.Name, "Sin")
}
func (c Chicken) GetName() string {
    return c.Name
}

type Cat struct {
    Name string
}

func (c Cat) Sing() {
    fmt.Println(c.Name, "Sing")
}
func (c Cat) GetName() string {
    return c.Name
}

/*
     func sing(c Chicken) {
        c.Sing()   // 把Chicken 类型改为接口
    }
*/
func sing(c SingInterface) {
    c.Sing()
     ch, static(状态) := c.(chicken)     // 类型断言 或
     switch name := c.(type){
     case Chicken:
         fmt.Println(name)
     case Cat:
          fmt.Println(name)
        default:
                 fmt.Println("其他")

     }
     
    fmt.Println(c.GetName())
}

func main() {
    c := Chicken{Name: "kunKun"}
    ch := Cat{Name: "Mimi"}
    sing(c)
    sing(ch)
}

空接口

空接口可以接收任何类型

type name interface{}

func PrintZ(test interface{} )  {
    fmt.Println(test)
}

泛型

泛型函数

func add[T int | float64 | int32](a, b T) T {
  return a + b
}

泛型结构体

type Responsed[T any] struct {
    Code int    `json:"code"`
    Msg  string `json:"msg"`
    Date T      `json:"date"`
}

func main() {
    type User struct {
        Name string `json:"name"`
    }
    type UserInfo struct {
        Name string `json:"name"`
        Age  int    `json:"age"`
    }

    var userResponse Responsed[User]
    var userInfoResponse Responsed[UserInfo]

    json.Unmarshal([]byte(`{"code":0,"msg":"sure","date":{"name":"wood"}}`), &userResponse)
    fmt.Println(userResponse.Date.Name)
    json.Unmarshal([]byte(`{"code":0,"msg":"sure","date":{"name":"fake","age":18}}`), &userInfoResponse)
    fmt.Println(userInfoResponse.Date.Name, userInfoResponse.Date.Age)
}

四:terminal 操作

  1. 格式化代码
gofmt –w .go 格式化并覆盖
gofmt -r '(a) -> a' –w *.go  将code中的 (a) 替换为 a 
  1. 查看代码文档
go doc package xx函数 可以查看具体包 具体函数用法
  1. 安装第三方包
go install 
  1. 升级版本
go fix
  1. 单元测试

测试文件命名为 xxx_test.go

go test

五: 函数

首字母大写可被外部调用

返回零值(或 nil)和 false 表示失败

// 有参有返回值的
func test(Datatype parameter)(return_datatype,return_datatype){
        // code.......
     return value,values
]

// 优先级 >> main 函数
// 初始化函数
func init() {
    
}
// 引用传递
func DoSomething(a *A) {
                b = a         // 通过指针传递,原始对象可以被修改,且 b 持有有效的指针引用。
}
func DoSomething(a A) {
                b = &a        // 通过值传递,原始对象不会被修改 
}
// 多个重复参数
func add(numberList ...int){

}

// 署名函数
func {
var getName = func() (name string) {
        name = "wood"
        return
    }
    fmt.Println(getName())
    }
    go func() { ... }()

高阶函数

    // _是函数名 == fun的名称 -> 1,2,3
var funMap = map[int]func _ (){
    1: login,
    2: register,
    3: exit,
}
fun, ok := funMap[index]
if ok{
    fun()
}

闭包

func AwaitAdd(awaitSecond int) func(...int) int {
    {
        return func(numberList ...int) (sum int) {
            for _, number := range numberList {
                sum += number
            }
            return sum
        }
    }
}

defer 函数

return 之前执行

距离return近谁先执行

用作与资源清理

在函数体执行完毕后再执行

六 : 流程控制

1. 条件

// 可以直接初始化变量用

if err := file.Chmod(0664); err != nil {
    fmt.Println(err)
    return err
}

switch var1 {
    case var1:
  // code
  case var2:
  // code2
  fallthrough; 
  // 执行当前的接着执行下一个
    case var3:
    // code3
  default:
}

2.循环

continue : 忽略剩余的循环体而直接进入下一次循环

Tag :标签功能 大写

LABEL1:
    for i := 0; i <= 5; i++ {
        for j := 0; j <= 5; j++ {
            if j == 4 {
                continue LABEL1
                // continue 指向LABEL1 跳转执行该标签内容
            }
            fmt.Printf("i is: %d, and j is: %d\n", i, j)
        }
    }
}
for i := 0; i < 5; i++ {
// code
}

for i, j := 0, N; i < j; i, j = i+1, j-1 {}

for i:=0; i<5; i++ {
    for j:=0; j<10; j++ {
        println(j)
    }
}

// 无条件循环 == while
for{}
 
// for-range == foreach
// 遍历
str := "Go is a beautiful language!"
    fmt.Printf("The length of str is: %d\n", len(str))
    for pos, char := range str {
        fmt.Printf("Character on position %d is: %c \n", pos, char)
        // pos 是index索引  char 指向的内容
    for index, rune := range str2 {
        fmt.Printf("%-2d      %d      %U '%c' % X\n", index, rune, rune, rune, []byte(string(rune)))

七: 多线程

var wait sync.WaitGroup

func main() {
    starttime := time.Now()
    wait.Add(3)
    go shopping("wood", &wait)
    go shopping("fuck", &wait)
    go shopping("cat", &wait)

    wait.Wait()
    fmt.Println("完成购买", time.Since(starttime))

}

func shopping(name string, wait *sync.WaitGroup) {
    fmt.Printf("%s 开始购物\n", name)
    time.Sleep(1 * time.Second)
    fmt.Printf("%s 结束\n", name)
    wait.Done()
}

channer 信道

var waat sync.WaitGroup
var moneyChan = make(chan int)

func main() {
    starttime := time.Now()
    waat.Add(3)
    go pay("wood", 2, &waat)
    go pay("fuck", 5, &waat)
    go pay("cat", 3, &waat)

    go func() {
        waat.Wait()
        close(moneyChan)
    }()

    for true {
        money, ok := <-moneyChan
        fmt.Println(money, ok)
        if !ok {
            break
        }
    }
//   or
for money := range moneyChan {
        fmt.Println(money)
    }
    fmt.Println("完成购买", time.Since(starttime))

}

func pay(name string, money int, wait *sync.WaitGroup) {
    fmt.Printf("%s 开始购物\n", name)
    time.Sleep(1 * time.Second)
    fmt.Printf("%s 结束\n", name)

    moneyChan <- money

    waat.Done()
}

select

var waat1 sync.WaitGroup
var moneyChan1 = make(chan int)
var nameChan = make(chan string)
var doneChan = make(chan struct{})

func main() {
    starttime := time.Now()
    waat1.Add(3)
    go send("wood", 2, &waat1)
    go send("fuck", 5, &waat1)
    go send("cat", 3, &waat1)

    go func() {
        defer close(moneyChan1)
        defer close(nameChan)
        defer close(doneChan)
        waat1.Wait()
    }()
    
    var moneyList []int
    var nameList []string
    var event = func() {
        for {
            select {
            case money := <-moneyChan1:
                moneyList = append(moneyList, money)
            case name := <-nameChan:
                nameList = append(nameList, name)
            case <-doneChan:

                return
            }
        }
    }
    event()
    fmt.Println("完成购买", time.Since(starttime))
    fmt.Println(nameList)
    fmt.Println(moneyList)
}

超时处理 Timeout

var done = make(chan struct{})

func event() {
    fmt.Println("event开始执行")
    time.Sleep(2 * time.Second)
    fmt.Println("event执行完毕")
    close(done)
}

func main() {
    go event()
    select {
    case <-done:
        fmt.Println("协程执行完毕")
    case <-time.After(1 * time.Second):
        fmt.Println("超时")
        return
    }
}

线程安全 lock

var sum2 int
var lock sync.Mutex
var wait2 sync.WaitGroup

func add1() {
    lock.Lock()
    for i := 0; i < 10000; i++ {
        sum2++
    }
    lock.Unlock()
    wait2.Done()
}
func sub1() {
    lock.Lock()
    for i := 0; i < 10000; i++ {
        sum2--
    }
    lock.Unlock()
    wait2.Done()
}

func main() {
    wait2.Add(2)
    go add1()
    go sub1()
    wait2.Wait()
    fmt.Println(sum2)
}

Map.sync

var wait6 sync.WaitGroup
var mp1 sync.Map

func read() {
    for {
        fmt.Println(mp1.Load("time"))
    }
    wait6.Done()
}
func writer1() {
    for {
        mp1.Store("time", time.Now().Format("2006-01-02 15:04:05"))
    }
    wait6.Done()
}
func main() {
    wait6.Add(2)
    go read()
    go writer1()
    wait6.Wait()
}

八 : 异常处理

向上抛

func div(a, b int) (res int, err error) {
    if b == 0 {
        err = errors.New("division by zero")
        return
    }
    res = a / b
    return
}

func server() (res int, err error) {
    res, err = div(10, 0)
    if err != nil {
        return
    }

    res++
    res += 2
    return
}

func main() {
    res, err := server()
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(res)
}

中断程序

func init() {
    _, err := os.ReadFile("dddd")
    if err != nil {
        println("error")
    }
}

func main() {
    fmt.Println("hello world")
}

恢复程序

func reading() {
    defer func() {
        err := recover()
        if err != nil {
            fmt.Println(err)
            fmt.Println(string(debug.Stack()))
        }
    }()
    var list []int = []int{1, 2}
    fmt.Println(list[1])
}

func main() {
    reading()

    fmt.Println("正常执行")
}

IX. 文件流

1. FileRead

一次性读取

func ReadAtOnce() {
    file, err := os.ReadFile("E:\\code\\go\\file\\text.txt")
    if err != nil {
        println(error.Error(err))
    }
    fmt.Println(string(file))
}

分片读取

func ShardReading() {
    file, err := os.Open("E:\\code\\go\\file\\text.txt")
    if err != nil {
        panic(err)
    }
    defer file.Close()
    for {
        var byteData = make([]byte, 12)
        n, err := file.Read(byteData)
        if err == io.EOF {
            break
        }
        fmt.Println(string(byteData[:n]))
    }
}

缓冲读取

func BufRead() {
    file, err := os.Open("E:\\code\\go\\file\\text.txt")
    if err != nil {
        panic(err)
    }
    defer file.Close()
    buf := bufio.NewReader(file)
    for {
        text, _, err := buf.ReadLine()
        if err == io.EOF {
            break
        }
        fmt.Println(string(text))
    }
}

缓冲选词

func BufRead2() {
    file, err := os.Open("E:\\code\\go\\file\\text.txt")
    if err != nil {
        panic(err)
    }
    defer file.Close()
    buf := bufio.NewScanner(file)
    buf.Split(bufio.ScanWords)
    var index int
    for buf.Scan() {
        index++
        fmt.Println(index, buf.Text())
    }
}

2. FileWrite

func main() {
    file, err := os.OpenFile("w.txt", os.O_RDWR|os.O_CREATE, 0777)
    if err != nil {
        panic(err)
    }
    defer file.Close()

    byteData, err := io.ReadAll(file)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(string(byteData))

    err = os.WriteFile("w.txt", []byte("hi"), 0777)
    fmt.Println(err)

    file1, err1 := os.Open("C:\\Users\\34659\\Pictures\\117922308_p0_master1200.jpg")
    if err1 != nil {
        fmt.Println(err1)
        return
    }
    defer file1.Close()
    wfile, err2 := os.OpenFile("girl.jpg", os.O_WRONLY|os.O_CREATE, 0777)
    if err2 != nil {
        fmt.Println(err2)
        return
    }
    defer wfile.Close()
    io.Copy(wfile, file1)
}

X : 单元测试

文件要以 _test.go 为后缀

func TestAdd(t *testing.T) {
    if ans := Add(1, 2); ans != 3 {
        t.Errorf("Add(1, 2) = %d; want 3", ans)
    }
    if num := Add(4, 5); num != 8 {
        t.Errorf("Add(4,5) = %d; want 8", num)
    }

子测试

 func TestAdd(t *testing.T) {
    t.Run("add1", func(t *testing.T) {
        if ans := Add(1, 2); ans != 3 {
            t.Errorf("Add(1, 2) = %d; want 3", ans)
        }
    })
    t.Run("add2", func(t *testing.T) {
        if num := Add(4, 5); num != 8 {
            t.Errorf("Add(4,5) = %d; want 8", num)
        }
    })
}
Log打印日志, 结束测试PASS
Logf格式化输出日志, 同时结束测试PASS
Error打印错误日志,结束测试FAIL
Errorf FAIL
Fatal打印致命日志,同时结束FAIL
FatalF FAIL

TestMain

func setup() {
    fmt.Println("setup")
}
func teardown() {
    fmt.Println("teardown")
}
func Test1(t *testing.T) {
    fmt.Println("Test1")
}
func Test2(t *testing.T) {
    fmt.Println("Test2")
}

func TestMain(m *testing.M) {
    setup()
    code := m.Run()
    teardown()
    os.Exit(code)
}

XI.与其他语言进行交互

https://learnku.com/docs/the-way-to-go/interact-with-other-languages/3581

XII: 反射

判断类型

func refType(obj any) {
    typeObj := reflect.TypeOf(obj)
    fmt.Println(typeObj, typeObj.Kind())
    tp := typeObj.Kind()
    // 判断类型
    switch tp {
    case reflect.Slice:
        fmt.Println("切片")
    case reflect.Map:
        fmt.Println("map")
    case reflect.Struct:
        fmt.Println("struct")
    case reflect.String:
        fmt.Println("string")
    }
}
func main() {
    refType(struct {
        Name string
    }{Name: "wood"})
    name := "wood"
    refType(name)
    refType([]string{"wood"})
    name1 := "风"

获取值

func reflectionGetValues(obj any) {
    value := reflect.ValueOf(obj)
    fmt.Println(value.Type())
    switch value.Kind() {
    case reflect.Int:
        fmt.Println(value.Int())
    case reflect.Struct:
        fmt.Println(value.Interface())
    case reflect.String:
        fmt.Println(value.String())

    }
}
func main(){
    reflectionGetValues(44)
}

修改值

func reflectionSetValues(obj any) {
    value := reflect.ValueOf(obj)
    elem := value.Elem()
    // 专门取指针反射的值
    switch elem.Kind() {
    case reflect.String:
        elem.SetString("枫枫知道")
    }
}
func main() {
    reflectionSetValues(&name1)
    fmt.Println(name1)
}

结构体反射