初始go

[TOC]

初始GO

基础语法

hello world

  1. 一个项目只有一个包main

    而且在main里面有一个func main

注释

1
2
3
4
//单行注释
/*
多行注释
*/

简单的程序

  1. 小程序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    	package main

    import "fmt"

    func main() {
    var name string = "awd"
    fmt.Println(name)
    name = "Awdawd"
    fmt.Println(name)
    var Int int = 2
    fmt.Println(Int, name)
    }
    • 注意Println的不一样的用法

变量

  1. 声明变量

    • 定义单个变量

      var 变量名 变量的类型

      var 变量名

      变量名 :=

    • 定义多个变量

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      package main

      import "fmt"

      func main() {

      var (
      name string = "ad"
      Int int = 9
      )
      fmt.Println(name)
      fmt.Println(Int, name)

      print(Int)
      }

      注意var()用法

    • 变量的初始值

      go语言可以为变量默认值

    • 自动推导

      使用变量名 :=不用加var

      1
      2
      3
      4
      5
      6
      7
      8
      9
      	package main

      import "fmt"

      func main() {
      name := "AWda"
      fmt.Println(name)
      }

    • 打印类型

      %T大写

    • 打印地址

      %p小写

    • _给这个赋任何值都应该该被抛弃

  2. 变量交换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package main

    import "fmt"

    func main() {
    var a int = 100
    var b int = 200
    a, b = b, a
    fmt.Println(a, b)
    }

  3. 变量的作用域

    • 如果存在全局变量和局部变量,在函数里面优先使用局部变量

常量

  1. 使用关键字const

  2. 也可以使用自动推导

    1
    2
    const d, e, c = "string", 3.14, 520
    const a int =4;
  3. iota 常计数器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    func main() {
    const (
    a = iota
    b
    c
    d = "haha"
    e
    f = 100
    g
    h = iota
    i
    )
    fmt.Println(a, b, c, d, e, f, g, h, i)
    }

    b=1,c=2

    e=haha会与上面的变量保持相同

    g=100同理

    h=7恢复计数

    i=8

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    	func main() {
    const (
    a = iota
    b
    c
    d = "haha"
    e
    f = 100
    g
    h = iota
    i
    )
    const (
    j = iota
    )
    fmt.Println(a, b, c, d, e, f, g, h, i, j)

    }

    //j=0;
    //是一组新的const

数据类型

  1. bool

    默认值为false

    打印格式是%t

  2. 整形

    • 有符号整型:int8int16int32int64int

    • 无符号整型:uint8uint16uint32uint64uint。分别表示 8 位、16 位、32 位、64 位和字节长度的无符号整数。

  3. 浮点型

    • 当规定输出的小数点时,go会四舍五入

      1
      2
      3
      4
      5
      6
      7
      func main() {
      var float float32 = 3.14
      var float2 float32 = 3.19
      fmt.Printf("%f\t%f\n", float, float2)
      fmt.Printf("%.1f\t%.1f", float, float2)
      }

      运行结果

      1
      2
      3
      3.140000        3.190000
      3.1 3.2

  4. 部分类型的别名

  5. string

    • 使用%s打印

    • 字符串拼接

      1
      2
      var str string = "AWDawd"
      fmt.Println(str+"awd")
  6. 和C一样的转义字符

  7. 数据类型的转换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    		a := 3
    b := 3.14
    fmt.Println((float64(a) + b))
    //将a转换为float64



    c:=float64(int(float64(a)))
    println(c)
    • 整形,浮点型不能转成bool
  8. 切片

    • append()向切片添加

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      	package main

      import "fmt"

      func main() {
      var ints []int = make([]int, 5)
      fmt.Printf("before\n")
      for _, v := range ints {
      fmt.Println(v)
      }
      fmt.Println("after")
      ints = append(ints, 2)
      ints = append(ints, 2312)
      for _, v := range ints {
      fmt.Println(v)
      }

      b := make([]int, 5)
      copy(b, ints)
      for _, v := range b {
      fmt.Println(v)
      }
      }
  9. map

    • 创建
      a:=make(map[key]value)

      1
      2
      3
      4
      5
      6
      	a := make(map[string]int)
      a["noe"] = 1
      a["two"] = 2
      for _, v := range a {
      fmt.Println(v)
      }
    • 读取

      v, ifHava := a["three"]

      • v代表了值
      • ifHava 类型是bool看是否存在
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      	func main() {
      a := make(map[string]int)
      a["noe"] = 1
      a["two"] = 2
      for _, v := range a {
      fmt.Println(v)
      }
      v, ifHava := a["three"]
      if ifHava == true {
      fmt.Println(v)
      } else {
      fmt.Println("NO")
      }
      }
    • 删除

      delete(a, "one")

      a是一个map

    • 代码

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      	func main() {
      a := [3]int{2, 3, 4}
      sum := 0
      for i := range a {
      sum += i
      }

      fmt.Println(sum)

      m := map[string]string{"a": "1", "b": "2"}

      for k, v := range m {
      fmt.Println(k, v)
      }

      }
      • for range

        前面的相当于下标,所以直接是key

  10. 结构体

    • 起别名+创建结构体

      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
      // 起别名
      type chg int

      // 定义一个结构体
      type zjy struct {
      name string
      high float64
      }

      func changeZjy(test *zjy) {
      test.high = 1.5
      test.name = "zjy is big pig"
      }

      func main() {
      var int1 chg = 2
      fmt.Println(int1)
      fmt.Printf("%T\n", int1)

      var test zjy
      test.high = 2.4
      test.name = "zjy"
      fmt.Println(test)

      changeZjy(&test)
      fmt.Println(test)
      }


  11. 将结构体变换类

    • 注意
      • 记得在外挂函数的时候传指针
      • 声明结构体,记得通过大小写来限定权限
    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
    type Person struct {
    name string
    age int
    high float64
    }

    func (this *Person) setName(name string) {
    this.name = name
    }

    func (this *Person) getName() string {
    return this.name
    }

    func (this *Person) Show() {
    fmt.Println(*this)
    }
    func main() {
    var zjy Person
    zjy.setName("zjy")
    fmt.Println(zjy.getName())
    fmt.Println(zjy.name)
    zjy.Show()
    zjy.age = 20
    zjy.high = 1.5
    zjy.Show()
    fmt.Println(zjy)
    }

算数运算符

  1. 基本的都和C语言一样,下面是不一样的
  2. 自增自减只有i++i--

关系运算符

  1. 和C语言一样

逻辑运算符

  1. C语言一样

位运算符

  1. &两个二进制数对应都为1,才为1

    相当于和

  2. |只要有1,就为 1

    相当于或

  3. 打印二进制(b是二进制的缩写)

    1
    fmt.Printf("%b", b)
  4. ^不同为1,相同为0

  5. << n左移n位

  6. >> n右移n位

输入和输出

使用fmt里面的scan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fmt.Printf("input:")
var a int
var b int
var str string
fmt.Scan(&a, &str, &b)

if str == "+" {
fmt.Println("a+b:", a+b)
} else if str == "-" {
fmt.Println("a-b:", a-b)
} else if str == "*" {
fmt.Println("a*b:", a*b)
} else if str == "/" {
fmt.Println("a/b:", float64(a/b))
} else {
fmt.Println("input error")
}

选择语句

if-else

注意不加小括号

1
2
3
4
5
	if a == 10 {
fmt.Println("a==10")
} else {
fmt.Println("a=", a)
}

switch

默认op为true

goop可以是任何数据类型

switch没有穿透性

1
2
3
4
5
6
7
8
	switch a {
case 1:
fmt.Println("case 1")
case 2:
fmt.Println("case 2")
default:
fmt.Println("default")
}

fallthrough可以提供穿透性

1
2
3
4
5
6
7
8
9
	switch str {
case "1":
fmt.Println("case 1")
fallthrough
case "2":
fmt.Println("case 2")
default:
fmt.Println("case else")
}

配合使用break可以跳出穿透

1
2
3
4
5
6
7
8
9
10
11
12
13
	str := "1"
switch str {
case "1":
fmt.Println("case 1")
fallthrough
case "2":
if str == "1" {
break
}
fmt.Println("case 2")
default:
fmt.Println("case else")
}

加强的swith

1
2
3
4
5
6
7
8
		switch {
case a <= 2:
fmt.Println("a<=2")
case a < 2 && a >= 0:
fmt.Println("a<2&&a>=0")
default:
fmt.Println("default")
}

死循环

1
2
3
for{

}

加强的for(遍历是数组和切片)

注意range会返回两个值,第一个是下标,第二个是value

1
2
3
4
5
6
7
8
9
10
	func main() {
str := ""
for i := 0; i < 26; i++ {
str += string('A' + i)
}
fmt.Println(str)
for i, v := range str {
fmt.Printf("%d:%c ", i, v)
}
}

字符串

  1. 求长度使用len

  2. java一样string是不可以修改的

  3. 字符串其他操作

    遍历查询string

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    		package main

    import "fmt"

    func main() {
    str := "awd"
    fmt.Println(len(str))
    for i := 0; i < len(str); i++ {
    fmt.Printf("%c", str[i])
    }
    }
  4. 数组

    1
    2
    3
    4
    5
    6
    	func main() {
    a := []int{1, 2, 3, 4}
    for i, v := range a {
    fmt.Println(i, v)
    }
    }

    数组可以直接打印

    1
    2
    3
    4
    5
    6
    7
    	func main() {

    ints := []int{1, 2, 3, 4, 5}//这是一个切片,没有固定的大小,像vector
    ints2 := [12]int{0}//这是一个数组

    log.Println(ints)
    }

    打印结果

    [1 2 3 4 5]

  5. 字符串

    1. 字符串的创建和转换

      • str := "hello":使用双引号或反引号创建字符串。
      • str := string([]byte{'h', 'e', 'l', 'l', 'o'}):将字符切片转换为字符串。
      • str := strconv.Itoa(123):将整数转换为字符串。
    2. 字符串的长度和索引

      • len(str):获取字符串的长度(单位为字节)。
      • str[index]:获取指定索引位置的字符。
    3. 字符串的拼接和分割

      • str := str1 + str2:将两个字符串拼接起来。
      • strings.Join(strs []string, sep string) string:将多个字符串拼接成一个字符串,中间用 sep 分隔。
      • strings.Split(str string, sep string) []string:将字符串按照 sep 分割成多个子串,返回一个字符串切片。
    4. 字符串的查找、比较和替换

      • strings.Contains(str string, substr string) bool:判断字符串 str 是否包含子串 substr
      • strings.Index(str string, substr string) int:返回子串 substr 在字符串 str 中第一次出现的位置,若不存在则返回 -1
      • strings.Replace(str string, old string, new string, n int) string:将字符串中的 old 替换为 new,如果指定了 n,则最多替换 n 次。
    5. 字符串的转换和格式化

      • strconv.Atoi(str string) (int, error):将字符串转换为整数。
      • strconv.ParseFloat(str string, bitSize int) (float64, error):将字符串转换为浮点数。
      • fmt.Sprintf(format string, a ...interface{}) string:类似于 Printf,但是返回一个字符串,而不是将结果输出到标准输出。

函数定义

  1. 一个加法函数

    多注意参数列表的省略

    1
    2
    3
    4
    func add(a, b int) int {
    return a + b
    }

  2. 一个传址的函数

    1
    2
    3
    	func add2(a, b *float64) float64 {
    return *a + *b
    }
  3. 形式参数,和实际参数

    形式参数:函数的参数列表

    实际参数:调用函数时传的参数

  4. 可变参数列表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    	
    func add3(args ...int) int {
    SUM := 0
    for _, v := range args {
    SUM += v
    }
    return SUM
    }

    • 可以使用len()计算可变参数长度

    • 每一个函数只能写一个一个可变参数

    • any

      1
      var ANY any
  5. 参数的传递

    • 值传递

      基础数据类型,array,struct

      注意使用传递数组的时候,我们需要将形参的数组的的的大小和实参数组的大小同一

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      	func test(ints [3]int) {
      fmt.Println(ints)
      ints[0] = 100
      fmt.Println(ints)
      }

      func main() {
      ints2 := [3]int{1, 2, 3} //这是一个数组
      fmt.Println(ints2)
      test(ints2)
      fmt.Println(ints2)
      }

      运行结果:

      [1 2 3]
      [1 2 3]
      [100 2 3]
      [1 2 3]

      可见没被更改

    • 引用传递

      切片

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      	func test(ints []int) {
      fmt.Println(ints)
      ints[0] = 100
      fmt.Println(ints)
      }

      func main() {
      ints2 := []int{1, 2, 3} //这是一个数组
      fmt.Println(ints2)
      test(ints2)
      fmt.Println(ints2)
      }

      运行结果

      [1 2 3]
      [1 2 3]
      [100 2 3]
      [100 2 3]

    • 直接传地址

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      	func test(ints *int) {
      fmt.Println(*ints)
      *ints = 100
      fmt.Println(*ints)
      }

      func main() {
      ints2 := 2
      fmt.Println(ints2)
      test(&ints2)
      fmt.Println(ints2)
      }

      运行结果

      2
      2
      100
      100

变量的作用域

  1. 近者优先使用

函数的递归

1
2
3
4
5
6
7
8
9
10
11
	func workOut(num int) int {
if num > 0 {
return num + workOut(num-1)
} else {
return 0
}
}

func main() {
fmt.Println(workOut(100))
}

推迟(延迟)函数

  1. defer 修饰调用函数

    表示在最后调用

  2. 如果有多条defer则defer语句会逆序调用,也就是类型栈,先声明的最后调用

  3. 表面上是最后执行,其实是顺序编译,放进调用栈,在这个时候就已经传参。所以出现多个defer时出现先调用后执行

函数的数据类型

  1. 函数本身也是一个数据了类型,类似C语言的函数指针

    func main()

    1
    2
    3
    4
    5
    6
    7
    8
    func main() {
    test()
    }

    func test() {
    fmt.Printf("%T", test) //打印函数的类型
    }

    运行结果

    func()

    func test() int

    1
    2
    3
    4
    5
    6
    7
    8
    9

    func main() {
    test()
    }

    func test() int {
    fmt.Printf("%T", test) //打印函数的类型
    return 1
    }

    运行结果

    func() int

    func(int, int) (int, int)

    1
    2
    3
    4
    5
    6
    7
    8
    	func main() {
    test(1, 2)
    }

    func test(a int, b int) (int, int) {
    fmt.Printf("%T", test) //打印函数的类型
    return 1, 2
    }

    运行结果

    func(int, int) (int, int)

  2. 类比函数指针

无名函数

  1. 通过函数类型进行函数赋值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    	func main() {
    var test2 func(int, int) (int, int)
    test2 = test
    test2(1, 2)

    }

    func test(a int, b int) (int, int) {
    fmt.Printf("%T", test) //打印函数的类型
    return 1, 2
    }

    可以看成C语言的函数,或者c++的可调用对象

  2. 无名函数

    相当于c++的lambda表达式

    不写函数名,直接写()

    1
    2
    3
    4
    5
    6
    	func main() {
    func(a, b int) {
    fmt.Println(a, b)
    fmt.Printf("this is lambda")
    }(1, 2)
    }
  3. 函数也可以当作函数的参数,就是回调函数

  4. 函数作为另一个函数的return ,可以形成闭包结构

闭包

//没学懂

结构体函数

  • 在func后面添加结构体

    参考代码实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    	type Student struct {
    name string
    ids string
    }

    func (s Student) getName() string {
    return s.name
    }

    func (s Student) getIds() string {
    return s.ids
    }

错误定义

  1. import "errors"

    errors.New(string)

    返回错误的类型

获取时间

  1. import "time"

数字的解析

  1. f, _ := strconv.ParseFloat("1.421", 64)

继承

继承&重载

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

type Father1 struct {
money string
name string
}

func (this *Father1) SetName(name string) {
this.name = name
}

type Father2 struct {
age int
matherName string
}

type Son struct {
Father1
Father2
}

func (this *Son) SetName(name string) {
this.name = name
}

func main() {
mySonZjy := Son{
Father1: Father1{"no money", "chg"},
Father2: Father2{19, " zjy&chg"},
}
fmt.Println(mySonZjy)

mySonZjy.Father1.SetName("this father name")
fmt.Println(mySonZjy)
mySonZjy.SetName("this is son name")
fmt.Println(mySonZjy)
}


多态

  1. 通过接口实现多态,也就是相当c++的纯虚基类

  2. 接口本质是一个指针

  3. 代码

    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
    // 多态的实现
    type Animal interface {
    //只能有函数
    GetType() string
    GetColor() string
    //kind string
    //color string
    }

    type Cat struct {
    kind string
    color string
    }

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

    type Dog struct {
    kind string
    color string
    }

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

    func GetAnimal(animal Animal) {
    fmt.Println("color is:", animal.GetColor())
    fmt.Println("type is :", animal.GetType())
    }

    func main() {
    cat := Cat{"Cat", "blue"}
    GetAnimal(&cat)

    dog := Dog{
    kind: "Dog",
    color: "yellow",
    }
    fmt.Println(dog)
    GetAnimal(&dog)
    }


万能类型

  1. interface{}相当于void

  2. 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    type Person struct {
    name string
    age int
    }

    func function(arg interface{}) {
    fmt.Println(arg)
    fmt.Printf("and type is: %T \n", arg)
    }

    func main() {
    person := Person{
    name: "chg",
    age: 20,
    }
    var f float32 = 2.5
    function(2.4)
    function(f)
    function(1)
    function(person)
    }


  3. 万能类型提供断言,可以查看是否是某种变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import "fmt"

    func IsString(arg interface{}) {
    value, isString := arg.(string)
    if isString {
    fmt.Println(value)
    fmt.Println("this is string")
    } else {
    fmt.Println(value) //不是的话打印换行符
    fmt.Println("this not string")
    }
    }

    func main() {
    IsString("string")
    IsString(3.4)
    }
  4. 变量里面的pair

    每一个变量都有一个pair于是可以对

反射

  1. reflect

    提供了两个函数用于获取变量的pair从而获取到值和类型

    这个用于对于未知类型变量的处理

  2. 结构体标签

    • 语法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      import (
      "fmt"
      "reflect"
      )

      type Person struct {
      Name string `info:"name" doc:"我的名字"`
      High float64 `info:"high"`
      Age int `info:"age"`
      }

      func findTag(T any) {
      str := reflect.TypeOf(T)
      for i := 0; i < str.NumField(); i++ {
      tag := str.Field(i).Tag
      fmt.Println(tag)
      }
      }

      func main() {
      var person Person
      findTag(person)
      }

线程和协程

  1. 创建goroutine相当于创建一个线程

    只用普通函数创建线程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    import (
    "fmt"
    "time"
    )

    func goRoutine() {
    for i := 0; i < 10; i++ {
    fmt.Println("this is goroutine : ", i)
    time.Sleep(time.Second)
    }
    }

    func main() {
    i := 0
    go goRoutine()
    for i < 10 {
    fmt.Println("this is main : ", i)
    time.Sleep(1 * time.Second)
    i++
    }
    }


    使用匿名函数创建线程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    func main() {
    go func() {
    defer fmt.Println("this is A.defer")
    i := 0
    for i < 10 {
    i++
    fmt.Println("this is goRoutine : ", i)
    time.Sleep(1 * time.Second)
    }
    fmt.Println("A")

    func() {
    runtime.Goexit() //退出当前的goroutine
    defer fmt.Println("this is B.defer")
    fmt.Println("this is B")
    }()
    }() //加小括号是为了调用


  2. 线程之间的沟通

    • chan

      使用chan 保持线程之间的联系,这个变量能够维持线程之间的秩序,保持main后退出。也就是说如果chan没有值,就会阻塞

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      func main() {
      defer fmt.Println("main.defer")
      var c chan any = make(chan any)

      go func() {
      defer fmt.Println("A.defer")
      c <- 888
      }()
      g := <-c
      fmt.Println(g)
      }
      • 无缓冲的chan

        当一个goroutine向无缓冲的chan发送数据时,如果没有其他goroutine正在等待接收数据,发送的goroutine会被阻塞,直到有其他goroutine准备好接收数据为止。同样地,当一个goroutine从无缓冲的chan接收数据时,如果没有其他goroutine正在等待发送数据,接收的goroutine也会被阻塞,直到有其他goroutine准备好发送数据为止。

        无缓冲的chan可以用于实现两个goroutine之间的同步,确保在数据交换之前两个goroutine都准备好。它们可以用于控制并发的执行顺序,防止数据竞争和资源争用。

        在例子中使用make(chan any)创建

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        func main() {
        defer fmt.Println("main.defer") // 创建了一个没有缓冲的channel
        var c chan any = make(chan any)

        go func() {
        defer fmt.Println("A.defer")
        c <- 888
        }()
        g := <-c
        fmt.Println(g)
        }
      • 有缓冲的chan

        有缓冲的chan允许在发送(chan <- value)和接收(value <- chan)数据时不会立即发生阻塞,除非缓冲区已满或为空。当缓冲区未满时,发送操作会将数据放入缓冲区,并立即返回,而不会阻塞发送的goroutine。同样地,当缓冲区不为空时,接收操作会从缓冲区中取出数据,并立即返回,而不会阻塞接收的goroutine

        当缓冲区已满时,发送操作会导致发送的goroutine阻塞,直到有其他goroutine从缓冲区中取出数据为止。同样地,当缓冲区为空时,接收操作会导致接收的goroutine阻塞,直到有其他goroutine向缓冲区发送数据为止。

        例子中使用make(chan int,3)进行创建

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
               
        func main() {
        defer fmt.Println("main 工作完毕")
        c := make(chan int, 3) // 创建了一个有三个缓冲的channel
        go func() {
        defer fmt.Println("子线程工作完毕")
        i := 0
        for i < 4 {
        i++
        c <- i
        fmt.Println("子线程 传输元素为:", i, " len(c) ", len(c), " cap(c) ", cap(c))

        }
        }()
        time.Sleep(time.Second * 2)
        for i := 0; i < 4; i++ {
        num := <-c
        fmt.Println("main 接收到元素为:", num, " len(c) ", len(c), " cap(c) ", cap(c))
        }
        time.Sleep(1 * time.Second)
        }

      • 关闭channel

      • channel和range的关系

        也就是说我们可以使用range遍历channel

      • channelselect

        可以多路的监控channel状态

GO


初始go
https://tsy244.github.io/2023/05/07/go/初始go/
Author
August Rosenberg
Posted on
May 7, 2023
Licensed under