断言、反射和Context
与其说是教程,更像是总结
一起学习
断言
断言的基本概念
把一个接口类型的东西,断言为他的原始结构,并且可以调用原始结构的方法和属性
/**
@Go version: 1.17.6
@project: TeachCode
@ide: GoLand
@file: TEST.go
@author: Lido
@time: 2022-03-05 22:33
@description: 断言
*/
package main
import "fmt"
type User struct {
name string
age int
sex int
}
type Student struct {
User
}
func (u User) SayHello() {
fmt.Println(u.name,u.sex,u.age)
}
func main() {
user := User{
name: "lihua",
age: 1,
sex: 2,
}
___check(user)
}
func ___check(v interface{}) {
//断言,确定v为User类型
v.(User).SayHello()
}
lihua 1 2
断言的应用
/**
@Go version: 1.17.6
@project: TeachCode
@ide: GoLand
@file: TEST.go
@author: Lido
@time: 2022-03-05 22:33
@description: 断言
*/
package main
import "fmt"
type User struct {
name string
age int
sex int
}
type Student struct {
User
}
func (u User) SayHello(name string) {
fmt.Println(name)
}
func main() {
user := User{
name: "lihua",
age: 1,
sex: 2,
}
Check(user)
s := Student{User{}}
Check(s)
}
func Check(v interface{}) {
//用判断来判断类型
switch v.(type) {
case User:
fmt.Printf("%T is User\n",v)
case Student:
fmt.Printf("%T is Student\n",v)
}
}
main.User is User
main.Student is Student
反射
反射的基本概念
反射就是解决大量的断言判断和修改
package main
import (
"fmt"
"reflect"
)
type User struct {
name string
age int
sex int
}
type Student struct {
User
}
func (u User) SayHello(name string) {
fmt.Println(name)
}
func main() {
user := User{
name: "liuhua",
age: 1,
sex: 2,
}
Check(user)
s := Student{User{}}
Check(s)
}
func Check(i interface{}) {
//判断类型
t := reflect.TypeOf(i)//直接反射出i的类型和值
v := reflect.ValueOf(i)
fmt.Println(t, v)
}
main.User {lihua 1 2}
main.Student 0
取值
func check(i interface{}) {
//判断类型
t := reflect.TypeOf(i)
v := reflect.ValueOf(i)
for i := 0; i < t.NumField(); i++ {
fmt.Println(v.Field(i))
}
}
lihua
1
2
多级取值
package main
import (
"fmt"
"reflect"
)
type User struct {
name string
age int
sex int
}
type Student struct {
classroom string
User
}
func main() {
s := Student{
"software engineering",
User{
name: "lihua",
age: 1,
sex: 2,
},
}
Check(s)
}
func Check(i interface{}) {
//判断类型
t := reflect.TypeOf(i)
v := reflect.ValueOf(i)
fmt.Println(t, v)
//取多层级 取出第一层中的第二个元素
fmt.Println(v.FieldByIndex([]int{0}))
fmt.Println(v.FieldByIndex([]int{1, 0}))
fmt.Println(v.FieldByIndex([]int{1, 1}))
fmt.Println(v.FieldByIndex([]int{1, 2}))
}
main.Student {software engineering {lihua 1 2}}
software engineering
lihua
1
2
fmt.Println(v.FieldByName("classroom"))
//software engineering
判断类型
func check(i interface{}) {
//判断类型
t := reflect.TypeOf(i)
ty := t.Kind()
if ty == reflect.Struct {
fmt.Println("I'm a Struct")
}
}
I'm a Struct
修改
package main
import (
"reflect"
)
type User struct {
name string
age int
sex int
}
type Student struct {
Classroom string
User
}
func main() {
s := Student{
"software engineering",
User{
name: "lihua",
age: 1,
sex: 2,
},
}
//要修改就要传入地址
change(&s)
}
func change(i interface{}) {
//判断类型
v := reflect.ValueOf(i) //&{software engineering {lihua 1 2}}
e := v.Elem() //{software engineering {lihua 1 2}}
e.FieldByName("Classroom").SetString("计算机科学") //&{计算机科学 {lihua 1 2}}
}
调用结构体中方法
package main
import (
"fmt"
"reflect"
)
type User struct {
name string
age int
sex int
}
type Student struct {
Classroom string
User
}
func (u User) SayHello(name string) {
fmt.Println("hello ", name)
}
func (u User) SayBye(name string) {
fmt.Println("bye ", name)
}
func (u User) SayAye(name string) {
fmt.Println("aye ", name)
}
func (u User) SayZye(name string) {
fmt.Println("zye ", name)
}
func main() {
user := User{
name: "lido",
age: 1,
sex: 2,
}
//要修改就要传入地址
change(user)
}
func change(i interface{}) {
//判断类型
v := reflect.ValueOf(i)
//spring IOC类似的操作
m := v.Method(0)//按顺序调用
m.Call([]reflect.Value{reflect.ValueOf("你好")})
m = v.Method(1)
m.Call([]reflect.Value{reflect.ValueOf("你好")})
m = v.Method(2)
m.Call([]reflect.Value{reflect.ValueOf("你好")})
m = v.Method(3)
m.Call([]reflect.Value{reflect.ValueOf("你好")})
}
Context
普通协程
package main
import (
"fmt"
"time"
)
func main() {
flag := make(chan bool)
messages := make(chan int)
//需要先打开管道
go son(flag, messages)
for i := 0; i < 3; i++ {
//再发送值
messages <- i
}
fmt.Println("主进程结束")
}
func son(flag chan bool, msg chan int) {
t := time.Tick(time.Second)
for _ = range t {
select {
case <-time.After(2 * time.Second):
fmt.Println("timeout")
return
case m := <-msg:
fmt.Printf("接收到的值: %d\n", m)
}
}
}
接收到的值: 0
接收到的值: 1
接收到的值: 2
主进程结束
context携带数据
func main() {
//相当于暂时保存数据
ctx := context.WithValue(context.Background(), "name", "lido")
ctx, clear := context.WithCancel(ctx)
messages := make(chan int)
go son(ctx, messages)
for i := 0; i < 3; i++ {
messages <- i
}
clear()//配合 case <-ctx.Done():
time.Sleep(time.Second)
fmt.Println("主进程结束")
}
func son(ctx context.Context, msg chan int) {
t := time.Tick(time.Second)
for _ = range t {
select {
case m := <-msg:
fmt.Printf("接收到的值: %d\n", m)
case <-ctx.Done():
fmt.Println("我结束了", ctx.Value("name"))
return
}
}
}
接收到的值: 0
接收到的值: 1
接收到的值: 2
我结束了 value!
主进程结束
设置超时时间
结束日期和超时时间
package main
import (
"context"
"fmt"
"time"
)
func main() {
//设置3秒超时
ctx, claer := context.WithTimeout(context.Background(), time.Second*3)
//设置结束日期
//ctx, claer := context.WithDeadline(context.Background(), time.Now().Add(time.Second*3))
messages := make(chan int)
go son(ctx, messages)
//发送5个值
for i := 0; i < 5; i++ {
messages <- i
}
claer()
time.Sleep(time.Second)
fmt.Println("主进程结束")
}
func son(ctx context.Context, msg chan int) {
//间隔接收
t := time.Tick(time.Second)
for _ = range t {
select {
case m := <-msg:
fmt.Printf("接收到的值: %d\n", m)
case <-ctx.Done():
fmt.Println("我结束了")
return
}
}
}
接收到的值: 0
接收到的值: 1
接收到的值: 2
我结束了
案例
模拟信息监控
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
var stop chan bool = make(chan bool)
func cpuInfo() {
defer wg.Done()
for {
select {
case <-stop:
fmt.Println("退出信息监控")
return
default:
time.Sleep(time.Second * 2) //每隔两秒读取一次
fmt.Println("读取信息完成")
}
}
}
func main() {
wg.Add(1)
go cpuInfo()
time.Sleep(time.Second * 6)
stop <- true
wg.Wait()
fmt.Println("信息监控完成")
}
读取信息完成
读取信息完成
读取信息完成
退出信息监控
信息监控完成
使用context的cancel后
package main
import (
"context"
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func Info(ctx context.Context) {
defer wg.Done()
for {
select {
case <- ctx.Done()://替换了 case <-stop
fmt.Println("退出监控")
return
default:
time.Sleep(time.Second) //每隔一秒读取一次
fmt.Println("读取信息完成")
}
}
}
func main() {
wg.Add(1)
ctx, cancel := context.WithCancel(context.Background())
go Info(ctx)
time.Sleep(time.Second * 6)
cancel()//代替 stop <- true
wg.Wait()
fmt.Println("信息监控完成")
}
读取信息完成
读取信息完成
读取信息完成
读取信息完成
读取信息完成
读取信息完成
退出监控
信息监控完成
context的多路监听
package main
import (
"context"
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func cpuInfo(ctx context.Context) {
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Println("退出CPU监控")
return
default:
time.Sleep(time.Second) //每隔一秒读取一次
fmt.Println("CPU读取信息完成")
}
}
}
func memoryInfo(ctx context.Context) {
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Println("退出内存监控")
return
default:
time.Sleep(time.Second) //每隔一秒读取一次
fmt.Println("内存读取信息完成")
}
}
}
func main() {
wg.Add(1)
ctx, cancel := context.WithCancel(context.Background())
go cpuInfo(ctx)
go memoryInfo(ctx)
time.Sleep(time.Second * 3)
cancel()
wg.Wait()
fmt.Println("CPU信息监控完成")
}
父子嵌套
package main
import (
"context"
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func cpuInfo(ctx context.Context) {
defer wg.Done()
ctx2, _ := context.WithCancel(ctx) //使用父节点
go memoryInfo(ctx2) //调用父节点,当父节点被取消时,子节点也会跟着一起被取消
for {
select {
case <-ctx.Done():
fmt.Println("退出CPU监控")
return
default:
time.Sleep(time.Second) //每隔一秒读取一次
fmt.Println("CPU读取信息完成")
}
}
}
func memoryInfo(ctx context.Context) {
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Println("退出内存监控")
return
default:
time.Sleep(time.Second) //每隔一秒读取一次
fmt.Println("内存读取信息完成")
}
}
}
func main() {
wg.Add(2)
ctx, cancel := context.WithCancel(context.Background())
go cpuInfo(ctx) //嵌套调用ctx
time.Sleep(time.Second * 2)
cancel() //两秒结束后,取消ctx
wg.Wait()
fmt.Println("信息监控完成")
}
其他context,也可以自己去实现他的接口
ctx,_ := context.WithCannel(ctx) //需要取消操作的ctx
ctx,_ := context.WithDeadline(ctx) //到点停止的ctx
ctx,_ := context.WithTimeout(ctx) //超时处理
ctx,_ := context.WithValue(ctx)
使用WithTimeout()
可以接收cancel,自己调用cancel()来结束(在主协程结束之前)
也可以自动调用
package main
import (
"context"
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func cpuInfo(ctx context.Context) {
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Println("退出CPU监控")
return
default:
time.Sleep(time.Second) //每隔一秒读取一次
fmt.Println("CPU读取信息完成")
}
}
}
func main() {
wg.Add(1)
ctx, _ := context.WithTimeout(context.Background(), 3*time.Second) //会自动结束,当然也可以手动cannel()
go cpuInfo(ctx) //嵌套调用ctx
time.Sleep(time.Second * 6)
wg.Wait()
fmt.Println("信息监控完成")
}