272_尚硅谷_管道的细节和课堂练习
1.channel 使用的注意事项
2.如果从 channel 取出数据后, 可以继续放入
package main
import (
"fmt"
)
// todo 演示管道的使用
func main() {
// 1. 创建一个可以存放3个int类型的管道
var intChan chan int
intChan = make(chan int, 3)
// 2. 看看intChan是什么
fmt.Printf("intChan 的值= %v intChan 本身的地址= %p\n", intChan, &intChan)
// 3. 向管道写入数据
intChan <- 10
intChan <- 20
intChan <- 30
// ! 如果从 channel 取出数据后, 可以继续放入
<-intChan // * 解释: 从intChan 取出数据不用了,理解为删除, 可以不赋值
// ! 注意点:当我们向管道写入数据时(案例是3个int),不能超过其容量, 但是可以边写入边读取
intChan <- 40
// 4. 看看管道的长度和容量(cap)
fmt.Println("=============== 4.看看管道的长度和容量(cap) ================")
fmt.Printf("len(intChan)= %v cap(intChan)= %v\n", len(intChan), cap(intChan))
// 5. 从管道读取数据
var num2 int
num2 = <-intChan // ! 注意点:当我们从管道读取数据时,如果管道中没有数据,就会阻塞等待
fmt.Println("=============== 5. 读取管道数据 ================")
fmt.Println("num2=", num2)
// 6. 取完数据后, 再看管道的长度和容量(cap)
fmt.Println("=============== 6. 取完数据后, 再看管道的长度和容量(cap) ================")
fmt.Printf("len(intChan)= %v cap(intChan)= %v\n", len(intChan), cap(intChan))
// 7. 在没有使用协程的情况下,如果管道数据全部取出,再取就会报错 deadlock
fmt.Println("=============== 7. 在没有使用协程的情况下,如果管道数据全部取出,再取就会报错 deadlock ================")
num3 := <-intChan
num4 := <-intChan
fmt.Println("num3=", num3, "num4=", num4)
}
3.如果从 channel 取出数据后, 可以继续放入_运行结果
4.1) 创建一个intChan,最多可以放3个int, 演示存3数据到intChan, 然后再取出这三个int
package main
import (
"fmt"
)
// todo 1) 创建一个intChan,最多可以放3个int, 演示存3数据到intChan, 然后再取出这三个int
func main() {
// 1. 创建一个可以存放3个int类型的管道
var intChan chan int
intChan = make(chan int, 3)
// 2. 看看intChan是什么
fmt.Printf("intChan 的值= %v intChan 本身的地址= %p\n", intChan, &intChan)
// 3. 向管道写入数据
intChan <- 10
intChan <- 20
intChan <- 30
// 4. 取值
num1 := <-intChan
num2 := <-intChan
num3 := <-intChan
fmt.Printf("=============== 1) 创建一个intChan, 最多可以放3个int, 演示存3数据到intChan, 然后再取出这三个int ===============\n")
fmt.Printf("num1= %v, num2= %v, num3= %v", num1, num2, num3)
}
5.2) 创建一个mapChan, 最多可以存放10个map[string]string 的key-val, 演示写出和写入![5.2) 创建一个mapChan, 最多可以存放10个map[string]string 的key-val, 演示写出和写入](https://img2024.cnblogs.com/blog/2358807/202603/2358807-20260304161201089-1428440537.png)
package main
import "fmt"
// todo 2) 创建一个mapChan, 最多可以存放10个map[string]string 的key-val, 演示写出和写入
func main() {
// 1) 创建一个mapChan,最多可以存放10个map[string]string
var mapChan chan map[string]string
// 2) 创建map并写入数据
mapChan = make(chan map[string]string, 10)
m1 := make(map[string]string, 20)
m1["city1"] = "北京"
m1["city2"] = "天津"
m2 := make(map[string]string, 20)
m2["hero1"] = "宋江"
m2["hero2"] = "武松"
mapChan <- m1
mapChan <- m2
// 使用for循环读取所有数据
// 注意: 需要重新创建管道,因为上面的代码已经读完了
fmt.Println("使用for循环读取:")
mapChan2 := make(chan map[string]string, 10)
mapChan2 <- m1
mapChan2 <- m2
// ! 关闭管道后可以使用range遍历
close(mapChan2)
// ! 注意:for range遍历管道(channel)的正确语法: for item := range channel {}
for m := range mapChan2 {
fmt.Println(m)
}
}
6.3) 创建一个catChan, 最多可以存放10个Cat结构体变量, 演示写入和读取的用法
package main
import "fmt"
type Cat struct {
Name string
Age int
}
// todo 3) 创建一个catChan, 最多可以存放10个Cat结构体变量, 演示写入和读取的用法
func main() {
// 1) 创建一个catChan, 最多可以存放10个Cat结构体变量
var catChan chan Cat
catChan = make(chan Cat, 10)
// 创建cat结构体
cat1 := Cat{Name: "tom1", Age: 18}
cat2 := Cat{Name: "tom2", Age: 20}
catChan <- cat1
catChan <- cat2
// 取出结构体内容
cat1_con := <-catChan
cat2_con := <-catChan
fmt.Printf("cat1_con= %v, cat2_con= %v", cat1_con, cat2_con)
}
7.4) 创建一个catChan2, 最多可以存放 10个Cat变量, 演示写入和读取的用法
package main
import "fmt"
type Cat struct {
Name string
Age int
}
// todo 4) 创建一个catChan2, 最多可以存放 10个*Cat变量, 演示写入和读取的用法
func main() {
// 1) 创建一个catChan2, 最多可以存放 10个*Cat变量
var catChan chan *Cat
catChan = make(chan *Cat, 10)
// 创建cat结构体
cat1 := Cat{Name: "tom1", Age: 18}
cat2 := Cat{Name: "tom2", Age: 20}
catChan <- &cat1
catChan <- &cat2
// 关闭通道(可选,但在读取完后关闭是好习惯)
close(catChan)
// 取出结构体内容
catFromChan1 := <-catChan
catFromChan2 := <-catChan
fmt.Printf("catFromChan1= %v, catFromChan2= %v", catFromChan1, catFromChan2)
}
8.5) 创建一个 allChan, 最多可以存放 10个 任意数据类型变量, 演示写入和读取的用法
package main
import "fmt"
type Cat struct {
Name string
Age int
}
// todo 5) 创建一个 allChan, 最多可以存放 10个 任意数据类型变量, 演示写入和读取的用法
func main() {
// 5) 创建一个 allChan, 最多可以存放 10个 任意数据类型变量
var allChan chan interface{} // ! 定义空接口
allChan = make(chan interface{}, 10)
// 创建cat结构体
cat1 := Cat{Name: "tom1", Age: 18}
cat2 := Cat{Name: "tom2", Age: 20}
// 给空接口类型填写数据
allChan <- cat1
allChan <- cat2
allChan <- 10
allChan <- "jack"
// 取出
allChancat1 := <-allChan
allChancat2 := <-allChan
v1 := <-allChan
v2 := <-allChan
fmt.Println("=============== 5) 创建一个 allChan, 最多可以存放 10个 任意数据类型变量, 演示写入和读取的用法 ===============")
fmt.Printf("allChancat1= %v, allChancat2= %v, v1= %v, v2= %v", allChancat1, allChancat2, v1, v2)
}
9.6) 查看代码输出内容
package main
import "fmt"
type Cat struct {
Name string
Age int
}
// todo 6) 查看代码输出内容
func main() {
// 6) 查看代码输出内容
var allChan chan interface{} // ! 定义空接口
allChan = make(chan interface{}, 10)
// 创建cat结构体
cat1 := Cat{Name: "tom1", Age: 18}
cat2 := Cat{Name: "tom2", Age: 20}
// 给空接口类型填写数据
allChan <- cat1
allChan <- cat2
allChan <- 10
allChan <- "jack"
// 取数据,
cat11 := <-allChan
fmt.Printf("cat11 type= %T, con= %v", cat11, cat11)
fmt.Println(cat11.Name) // ! 报错: cat11.Name undefined (type interface{} has no field or method Name)
}
10.使用类型断言,取出接口中结构体下指定字段的内容

package main
import "fmt"
type Cat struct {
Name string
Age int
}
func main() {
// 定义一个存放任意数据类型的管道 3个数据
allChan := make(chan interface{}, 3)
allChan <- 10
allChan <- "tom jack"
cat := Cat{"cat1", 4}
allChan <- cat
// 希望单独获得管道中第3个元素,则先将前两个推出
<-allChan
<-allChan
newCat := <-allChan // ! 注: 如果直接newCat.Name会报错, newCat是一个接口类型, 不能直接取字段内容
fmt.Printf("newCat_type= %T, newCat= %v\n", newCat, newCat)
fmt.Printf("=============== 注: 如果直接newCat.Name会报错, newCat是一个接口类型, 不能直接取字段内容, 编译不通过 ===============\n")
// fmt.Printf("newCat.Name= %v", newCat.Name)
// ! 使用类型断言后, 类型不改变, 结构体可以取出单独字段内容
a := newCat.(Cat)
fmt.Printf("=============== 使用类型断言, 类型不改变, 结构体可以取出单独字段内容 ===============\n")
fmt.Printf("a type= %T, a.Name= %v", a, a.Name)
}
浙公网安备 33010602011771号