断言、反射和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("信息监控完成")
}
