扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
基本设计思路:
成都创新互联-专业网站定制、快速模板网站建设、高性价比旌德网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式旌德网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖旌德地区。费用合理售后完善,十余年实体公司更值得信赖。
类型转换、类型断言、动态派发。iface,eface。
反射对象具有的方法:
编译优化:
内部实现:
实现 Context 接口有以下几个类型(空实现就忽略了):
互斥锁的控制逻辑:
设计思路:
(以上为写被读阻塞,下面是读被写阻塞)
总结,读写锁的设计还是非常巧妙的:
设计思路:
WaitGroup 有三个暴露的函数:
部件:
设计思路:
结构:
Once 只暴露了一个方法:
实现:
三个关键点:
细节:
让多协程任务的开始执行时间可控(按顺序或归一)。(Context 是控制结束时间)
设计思路: 通过一个锁和内置的 notifyList 队列实现,Wait() 会生成票据,并将等待协程信息加入链表中,等待控制协程中发送信号通知一个(Signal())或所有(Boardcast())等待者(内部实现是通过票据通知的)来控制协程解除阻塞。
暴露四个函数:
实现细节:
部件:
包: golang.org/x/sync/errgroup
作用:开启 func() error 函数签名的协程,在同 Group 下协程并发执行过程并收集首次 err 错误。通过 Context 的传入,还可以控制在首次 err 出现时就终止组内各协程。
设计思路:
结构:
暴露的方法:
实现细节:
注意问题:
包: "golang.org/x/sync/semaphore"
作用:排队借资源(如钱,有借有还)的一种场景。此包相当于对底层信号量的一种暴露。
设计思路:有一定数量的资源 Weight,每一个 waiter 携带一个 channel 和要借的数量 n。通过队列排队执行借贷。
结构:
暴露方法:
细节:
部件:
细节:
包: "golang.org/x/sync/singleflight"
作用:防击穿。瞬时的相同请求只调用一次,response 被所有相同请求共享。
设计思路:按请求的 key 分组(一个 *call 是一个组,用 map 映射存储组),每个组只进行一次访问,组内每个协程会获得对应结果的一个拷贝。
结构:
逻辑:
细节:
部件:
如有错误,请批评指正。
import (
"fmt"
"reflect"
)
func reflecType(x interface{}){
v := reflect.TypeOf(x)
fmt.Println("type:%v\n", v)
fmt.Println("type name:%v , rtpe kind:%v \n", v.getName(), v.getType())
}
type Cat struct{}
//通过反射设置变量的值
func reflectSetValue1(x interface{}){
v := reflect.ValueOf(x)
if v.Kind() == reflect.Int64{
v.SetInt(200) //修改的是副本, reflect 包会引发panic
}
}
//通过反射设置变量的值
func reflectSetValue2(x interface{}){
v := reflect.ValueOf(x)
//反射中使用Elem()获取指针对应的值
if v.Elem().Kind() == reflect.Int64{
v.Elem().SetInt(200)
}
}
func main(){
var a float32 = 3.14
reflectType(a) //type name:float32 type kind:float32
var b int64 = 100
reflectType(b) // type name :int64 type kind :int64
var c = Cat{}
reflectType(c) // type name :Cat type kind :struct
reflectSetValue1(b)
fmt.Println(b) //依然为100
reflectSetValue2(b)
}
维基百科中反射的定义:在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
golang reflect包实现了反射。动态的获得程序运行时对象的结构和信息。
reflect 包中提供了两个基础的关于反射的函数来获取上述的接口和结构体:
func TypeOf(i interface{}) Type
func ValueOf(i interface{}) Value
大体上可以这样理解,TypeOf获取对象的类型信息,ValueOf获取对象中存储的值。
golang tag
golang中可以为结构体的字段添加tag。golang本身的encoding/json包解析json使用了tag,一些开源的orm框架如gorm,也使用了tag。tag可以方便的为结构体的字段添加一些信息,用reflect可以读取到,加以利用。
这是一个用tag标记列名以实现结构体自动生成xlsx的例子:
```
type Employee struct{
ID int `xlsx:”工号”`
Name string `xlsx:”姓名”`
Email string `xlsx:”邮箱”`
}
func Outputxlsx(es []*Employee) ([]byte, error) {
xt := reflect.TypeOf(es[0])
xv := reflect.ValueOf(es[0])
rows := [][]interface{}{}
headers := []interface{}{}
for i := 0; i xt.Elem().NumField(); i++ {
head, ok := xt.Elem().Field(i).Tag.Lookup("xlsx")
if ok {
headers = append(headers, head)
}
}
for _, e := range es {
cells := []interface{}{}
xv := reflect.ValueOf(e)
for i := 0; i xv.Elem().NumField(); i++ {
_, ok := xt.Elem().Field(i).Tag.Lookup("xlsx")
if ok {
cells = append(cells, xv.Elem().Field(i).Interface())
}
}
rows = append(rows, cells)
}
file := xlsx.NewFile()
sheet, _ := file.AddSheet("sheet1")
row := sheet.AddRow()
for _, header := range headers {
row.AddCell().Value = fmt.Sprintf("%v", header)
}
for _, v := range rows {
row := sheet.AddRow()
for _, vv := range v {
row.AddCell().Value = fmt.Sprintf("%v", vv)
}
}
var buffer bytes.Buffer
if err := file.Write(buffer); err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
```
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流