当前位置: 首页 > news >正文

9、面向对象、泛型与反射

目录

  • 一、构造函数
  • 二、继承与重写
  • 三、泛型
  • 四、反射
    • 1 - 反射的基本概念
    • 2 - 反射的基础数据类型
    • 3 - 反射API
        • a - 获取Type类型
        • b - 获取struct成员变量的信息
        • c - 获取struct成员方法的信息
        • d - 获取函数的信息
        • e - 判断类型是否实现了某接口
  • 五、reflect.Value
        • a - 空value判断
        • b - 获取Value
        • c - 指针Value和非指针Value互相转换
        • d - 获取Value对应的原始数据
        • e - 通过Value修改原始数据的值
        • f - 通过Value修改slice
        • g - 通过Value修改map
  • 六、反射创建对象
  • 七、反射调用函数和成员方法

一、构造函数

  • 定义User结构体
type User struct {Name string //""表示未知Age  int    //-1表示未知Sex  byte   //1男,2女,3未知
}func main() {u := User{}     //构造一个空的User,各字段都取相应数据类型的默认值up := new(User) //构造一个空的User,并返回其指针
}
  • 自定义构造函数
func NewDefaultUser() *User {return &User{Name: "",Age:  -1,Sex:  3,}
}func NewUser(name string, age int, sex byte) *User {return &User{Name: name,Age:  age,Sex:  sex,}
}
  • 单例模式:确保在并发的情况下,整个进程里只会创建struct的一个实例
type User struct {Name string //""表示未知Age  int    //-1表示未知Sex  byte   //1男,2女,3未知
}func NewDefaultUser() *User {return &User{Name: "",Age:  -1,Sex:  3,}
}var (sUser *UseruOnce sync.Once
)func GetUserInstance() *User {uOnce.Do(func() { //确保即使在并发的情况下,下面的3行代码在整个go进程里只会被执行一次if sUser == nil {sUser = NewDefaultUser()}})return sUser
}func main() {//调用GetUserInstance()得到的是同一个User实例su1 := GetUserInstance()su2 := GetUserInstance()//修改su1会影响su2fmt.Println(su1.Age, su2.Age) //-1 -1su1.Age = 20fmt.Println(su2.Age) //20
}

二、继承与重写

  • 继承的实现:通过嵌入匿名结构体,变相实现“继承”的功能,因为访问匿名成员时可以跳过成员名直接访问它的内部成员
type Plane struct {color string
}
type Bird struct {Plane
}func main() {bird := Bird{}bird.Plane.color = "red"fmt.Println(bird.color) //red
}
  • 重写的实现
type Plane struct {color string
}func (pl Plane) fly() {fmt.Println("plane fly")
}type Bird struct {Plane
}func (bd Bird) fly() {fmt.Println("bird fly")
}func main() {bird := Bird{}bird.Plane.color = "red"fmt.Println(bird.Plane.color) //redfmt.Println(bird.color)       //redbird.Plane.fly() //plane flybird.fly()       //bird fly
}
  • 组合:严格意义上来说Go语言并不支持继承,它只是支持组合
type Plane struct{}
type Car struct{}//Bird组合了Plane和Car的功能
type Bird struct {PlaneCar
}

三、泛型

  • 使用泛型之前:在有泛型之前,同样的功能需要为不同的参数类型单独实现一个函数
func add4int(a, b int) int {return a + b
}
func add4float32(a, b float32) float32 {return a + b
}
func add4string(a, b string) string {return a + b
}
  • 使用泛型之后
type Addable interface { //类型约束int | string
}func add[T Addable](a, b T) T {return a + b
}func main() {fmt.Println(add(1, 2))             //3fmt.Println(add("hello", "world")) //helloworld
}

四、反射

1 - 反射的基本概念

  • 什么是反射:反射就是在运行期间(不是编译期间)探知对象的类型信息和内存结构、更新变量、调用它们的方法
  • 反射的使用场景
    • 函数的参数类型是interface{},需要在运行时对原始类型进行判断,针对不同的类型采取不同的处理方式。比如json.Marshal(v interface{})
    • 在运行时根据某些条件动态决定调用哪个函数,比如根据配置文件执行相应的算子函数
  • 反射的弊端
    • 代码难以阅读,难以维护
    • 编译期间不能发现类型错误,覆盖测试难度很大,有些bug需要到线上运行很长时间才能发现,可能会造成严重用后
    • 反射性能很差,通常比正常代码慢一到两个数量级。在对性能要求很高,或大量反复调用的代码块里建议不要使用反射

2 - 反射的基础数据类型

  • 反射的基础数据类型
    在这里插入图片描述
  • reflect.Type用于获取类型相关的信息
type Type interface {Method(int) Method                                           //第i个方法MethodByName(string) (Method, bool)                          //根据名称获取方法NumMethod() int                                              //方法的个数Name() string                                                //获取结构体名称PkgPath() string                                             //包路径Size() uintptr                                               //占用内存的大小String() string                                              //获取字符串表述Kind() Kind                                                  //数据类型Implements(u Type) bool                                      //判断是否实现了某接口AssignableTo(u Type) bool                                    //能否赋给另外一种类型ConvertibleTo(u Type) bool                                   //能否转换为另外一种类型Elem() Type                                                  //解析指针Field(i int) StructField                                     //第i个成员FieldByIndex(index []int) StructField                        //根据index路径获取嵌套成员FieldByName(name string) (StructField, bool)                 //根据名称获取成员FieldByNameFunc(match func(string) bool) (StructField, bool) //根据匹配函数匹配需要的字段Len() int                                                    //容器的长度NumIn() int                                                  //输出参数的个数NumOut() int                                                 //返回参数的个数
}
  • reflect.Value用于修改原始数据类型里的值
type Value struct {typ *rtype         // 代表的数据类型ptr unsafe.Pointer // 指向原始数据的指针
}

3 - 反射API

a - 获取Type类型


type User struct {age    int64Gender bool `json:"sex"`uint8
}type Student struct {User
}func get_type() {typeI := reflect.TypeOf(2)typeS := reflect.TypeOf("abc")fmt.Println(typeI)                          //int -> reflect.Typefmt.Printf("%s %T\n", typeI, typeI)         //int *reflect.rtypefmt.Println(typeI.String())                 //int -> stringfmt.Println(typeS)                          //string -> reflect.Typefmt.Println(typeI.Kind() == reflect.Int)    //true -> reflect.Kindfmt.Println(typeS.Kind() == reflect.String) //true -> reflect.Kindfmt.Println("-------------------")user := &User{}typeUser := reflect.TypeOf(user)fmt.Println(typeUser)                                 //*main.Userfmt.Println(typeUser.Elem())                          //main.Userfmt.Println(typeUser.Elem().Name())                   //Userfmt.Println(typeUser.Kind() == reflect.Ptr)           //true -> ptrfmt.Println(typeUser.Elem().Kind() == reflect.Struct) //true -> structfmt.Println("-------------------")user2 := &User{}typeUser2 := reflect.TypeOf(user2)fmt.Println(typeUser2.Size())fmt.Println(typeUser2.PkgPath())
}

b - 获取struct成员变量的信息

type User struct {age    int64Gender bool `json:"sex"`uint8
}type Student struct {Name stringuser User
}func get_field() {typeUser := reflect.TypeOf(User{}) //需要用struct的Type,不能用指针的TypefieldNum := typeUser.NumField()    //成员变量的个数for i := 0; i < fieldNum; i++ {field := typeUser.Field(i)fmt.Println(field.Name)            //变量名称fmt.Println(field.Offset)          //相对于结构体首地址的内存偏移量,string类型会占据16个字节fmt.Println(field.Anonymous)       //是否为匿名成员fmt.Println(field.Type)            //数据类型,reflect.Type类型fmt.Println(field.IsExported())    //包外是否可见(即是否以大写字母开头)fmt.Println(field.Tag.Get("json")) //获取成员变量后面``里面定义的tagfmt.Println("------------------")}//获取指定成员变量的信息if field, ok := typeUser.FieldByName("Gender"); ok {fmt.Println(field.Name)            //Genderfmt.Println(field.Offset)          //8fmt.Println(field.Anonymous)       //falsefmt.Println(field.Type)            //boolfmt.Println(field.IsExported())    //truefmt.Println(field.Tag.Get("json")) //sexfmt.Println("------------------")} else {fmt.Println("结构体中没有名为Gender的成员变量")}//根据index获取成员变量信息field := typeUser.FieldByIndex([]int{0}) //使用切片可以兼容嵌套fmt.Println(field.Name)                  //agefmt.Println(field.Offset)                //0fmt.Println(field.Anonymous)             //falsefmt.Println(field.Type)                  //int64fmt.Println(field.IsExported())          //falsefmt.Println(field.Tag.Get("json"))fmt.Println("------------------")//使用切片可以兼容嵌套typeStudent := reflect.TypeOf(Student{})fieldUser := typeStudent.FieldByIndex([]int{1, 0})fmt.Println(fieldUser.Name) //age
}

c - 获取struct成员方法的信息

type User struct {age    int64Gender bool `json:"sex"`uint8
}type Student struct {Name stringuser User
}func (*Student) Examine1(a int, b float32) (byte, string) {return byte(3), "abc"
}func (Student) Examine2(a int, b float32) (byte, string) {return byte(3), "abc"
}func get_method_info() {typeStudent := reflect.TypeOf(Student{})foreachMethod(typeStudent) //Examine2 -> 不会取到指针的方法ptypeStudent := reflect.TypeOf(&Student{})foreachMethod(ptypeStudent) //Examine1 //Examine2 -> Examine2也属于指针的方法//根据名称获取if method, ok := typeStudent.MethodByName("Examine2"); ok {fmt.Println(method.Name)fmt.Println(method.Type)fmt.Println(method.IsExported())fmt.Println(method.Type.NumIn())fmt.Println(method.Type.NumOut())}
}func foreachMethod(rt reflect.Type) {methodNum := rt.NumMethod()for i := 0; i < methodNum; i++ {method := rt.Method(i)fmt.Println(method.Name)fmt.Println(method.Type)fmt.Println(method.IsExported())fmt.Println(method.Type.NumIn())fmt.Println(method.Type.NumOut())fmt.Println("-------------")}
}

d - 获取函数的信息

func Add(a, b int) int {return a + b
}func main() {addType := reflect.TypeOf(Add)fmt.Printf("is function type %t\n", addType.Kind() == reflect.Func) //trueargInNum := addType.NumIn()                                         //输入参数的个数argOutNum := addType.NumOut()                                       //输出参数的个数for i := 0; i < argInNum; i++ {argTyp := addType.In(i)fmt.Printf("第%d个输入参数的类型%s\n", i, argTyp)}for i := 0; i < argOutNum; i++ {argTyp := addType.Out(i)fmt.Printf("第%d个输出参数的类型%s\n", i, argTyp)}
}

e - 判断类型是否实现了某接口

type People interface {Examine1(a int, b float32) (byte, string)
}type User struct {age    int64Gender bool `json:"sex"`uint8
}type Student struct {Name stringuser User
}func (*Student) Examine1(a int, b float32) (byte, string) {return byte(3), "abc"
}func convert() {userType := reflect.TypeOf(User{})studentType := reflect.TypeOf(Student{})fmt.Println(userType.AssignableTo(studentType))  //falsefmt.Println(studentType.AssignableTo(userType))  //falsefmt.Println(userType.ConvertibleTo(studentType)) //falsefmt.Println(studentType.ConvertibleTo(userType)) //falseuserType2 := reflect.TypeOf(User{})fmt.Println(userType.AssignableTo(userType2))  //truefmt.Println(userType2.ConvertibleTo(userType)) //true
}func impl() {//接口类型获取type的实现方法,nil可以理解为People指针的实例peopleType := reflect.TypeOf((*People)(nil)).Elem()userType := reflect.TypeOf(User{})studentType := reflect.TypeOf(Student{})pstudentType := reflect.TypeOf(&Student{})fmt.Println(userType.Implements(peopleType))     //falsefmt.Println(studentType.Implements(peopleType))  //falsefmt.Println(pstudentType.Implements(peopleType)) //true Student的指针才实现了People的接口
}

五、reflect.Value

a - 空value判断

func is_empty() {var i interface{}vl := reflect.ValueOf(i)fmt.Println(vl)           //<invalid reflect.Value>fmt.Println(vl.IsValid()) //falsevar user *User //nilvl = reflect.ValueOf(user)fmt.Println(vl) //<nil>if vl.IsValid() {fmt.Println(vl.IsNil()) //true}var u Uservl = reflect.ValueOf(u)fmt.Println(vl) //{0 false 0}if vl.IsValid() {fmt.Println(vl.IsZero()) //true}}

b - 获取Value

type User struct {age    int64Gender bool `json:"sex"`uint8
}func main() {iValue := reflect.ValueOf(1)sValue := reflect.ValueOf("hello")fmt.Println(iValue)                          //1fmt.Println(sValue)                          //hellofmt.Println(iValue.Kind() == reflect.Int)    //true -> intfmt.Println(sValue.Kind() == reflect.String) //true -> string// Value转TypeiType := iValue.Type()sType := sValue.Type()fmt.Println(iType.Kind() == reflect.Int)    //true -> intfmt.Println(sType.Kind() == reflect.String) //true -> string
}

c - 指针Value和非指针Value互相转换

type User struct {age    int64Gender bool `json:"sex"`uint8
}func main() {userPtrValue := reflect.ValueOf(&User{3, true, 6})userValue := userPtrValue.Elem()                    //Elem() 指针Value转为非指针Valuefmt.Println(userValue.Kind(), userPtrValue.Kind())  //struct ptruserPtrValue2 := userValue.Addr()                   //Addr() 非指针Value转为指针Valuefmt.Println(userValue.Kind(), userPtrValue2.Kind()) //struct ptr}

d - 获取Value对应的原始数据

- 通过Interface()函数把Value转为interface{},再从interface{}强制类型转换,转为原始数据类型
- 在Value上直接调用Int()、String()等
type User struct {age    int64Gender bool `json:"sex"`uint8
}func main() {iValue := reflect.ValueOf(1)sValue := reflect.ValueOf("hello")fmt.Printf("origin value iValue is %d %d\n", iValue.Interface().(int), iValue.Int())       //origin value iValue is 1 1fmt.Printf("origin value sValue is %s %s\n", sValue.Interface().(string), sValue.String()) //origin value sValue is hello hellouserValue := reflect.ValueOf(User{3, true, 6})user := userValue.Interface().(User)fmt.Printf("age=%d gender=%t uint=%d\n", user.age, user.Gender, user.uint8) //age=3 gender=true uint=6userPtrValue := reflect.ValueOf(&User{2, false, 5})user2 := userPtrValue.Interface().(*User)fmt.Printf("age=%d gender=%t uint=%d\n", user2.age, user2.Gender, user2.uint8) //age=2 gender=false uint=5}

e - 通过Value修改原始数据的值

  • 通过反射修改原始数据的值
    • 要想修改原始数据的值,给ValueOf传的必须是指针,而指针Value不能调用Set和FieldByName方法,所以得先通过Elem()转为非指针Value
    • 未导出成员的值不能通过反射进行修改,所以在修改前需要先进行CanSet判断
func main() {var i int = 18iValue := reflect.ValueOf(&i)iValue.Elem().SetInt(28)fmt.Println(i) //28user := User{10, true, 3}userValue := reflect.ValueOf(&user)fieldGenderValue := userValue.Elem().FieldByName("Gender")fieldGenderValue.SetBool(false)fmt.Println(user.Gender) //falsefieldAgeValue := userValue.Elem().FieldByName("age") //age是未导出的,所以我们需要先使用CanSet判断是否导出再进行设置值//fieldAgeValue.SetInt(8)                              //reflect: reflect.Value.SetInt using value obtained using unexportedif fieldAgeValue.CanSet() {fieldAgeValue.SetInt(8)} else {fmt.Println("age成员未导出,不可以set") //以小写字母开头的成员相当于是私有成员}
}

f - 通过Value修改slice

type User struct {age    int64Gender bool `json:"sex"`uint8
}func main() {users := make([]*User, 1, 5) //len=1,cap=5users[0] = &User{18, true, 8}sliceValue := reflect.ValueOf(&users) //准备通过Value修改users,所以传users的地址if sliceValue.Elem().Len() > 0 {      //取得slice的长度sliceValue.Elem().Index(0).Elem().FieldByName("Gender").SetBool(false)fmt.Printf("1st user Gender change to %t\n", users[0].Gender) //1st user Gender change to false}//修改slice的lensliceValue.Elem().SetLen(2)//调用reflect.Value的Set()函数修改其底层指向的原始数据sliceValue.Elem().Index(1).Set(reflect.ValueOf(&User{10, false, 3}))fmt.Printf("2nd user age %d\n", users[1].age) //2nd user age 10//修改slice的cap,新的cap必须位于原始的len到cap之间,即只能把cap改小fmt.Printf("slice old cap is %d\n", cap(users)) //slice old cap is 5sliceValue.Elem().SetCap(3)fmt.Printf("slice new cap is %d\n", cap(users)) //slice new cap is 3
}

g - 通过Value修改map

  • 反射修改map
    • Value.SetMapIndex()函数:往map里添加一个key-value对
    • Value.MapIndex()函数: 根据Key取出对应的map
type User struct {age    int64Gender bool `json:"sex"`uint8
}func main() {u1 := &User{1, true, 2}u2 := &User{3, true, 5}userMap := make(map[int]*User, 5)userMap[0] = u1mapValue := reflect.ValueOf(&userMap) //传userMap的地址mapValue.Elem().SetMapIndex(reflect.ValueOf(1), reflect.ValueOf(u2))for k, user := range userMap {fmt.Printf("key = %d, user age = %d\n", k, user.age)}mapValue.Elem().MapIndex(reflect.ValueOf(0)).Elem().FieldByName("Gender").SetBool(false)fmt.Println("u1 Gender = ", u1.Gender) //u1 age =  false
}

六、反射创建对象

  • 通过反射创建struct
type User struct {age    int64Gender bool `json:"sex"`uint8
}func main() {userType := reflect.TypeOf(User{1, false, 2})value := reflect.New(userType) //根据reflect.Type创建一个对象,得到该对象的指针,再根据指针提到reflect.Valuevalue.Elem().FieldByName("Gender").SetBool(true)if userOrign, ok := value.Interface().(*User); ok { //把反射类型转成go原始数据类型Call([]reflect.Value{})fmt.Println(userOrign.Gender) //true}}
  • 通过反射创建slice
type User struct {age    int64Gender bool `json:"sex"`uint8
}func main() {sliceType := reflect.TypeOf([]User{})sliceValue := reflect.MakeSlice(sliceType, 2, 3)sliceValue.Index(0).Set(reflect.ValueOf(User{1, false, 2}))sliceValue.Index(1).Set(reflect.ValueOf(User{3, true, 5}))users := sliceValue.Interface().([]User)fmt.Printf("1st user age %d\n", users[0].age)       //1fmt.Printf("2st user Gender %t\n", users[1].Gender) //true}
  • 通过反射创建map
type User struct {Id     intage    int64Gender bool `json:"sex"`Name   string
}func main() {var userMap map[int]*UsermapType := reflect.TypeOf(userMap)// mapValue:=reflect.MakeMap(mapType)mapValue := reflect.MakeMapWithSize(mapType, 10)user := &User{1, 1, false, "Jack"}key := reflect.ValueOf(user.Id)mapValue.SetMapIndex(key, reflect.ValueOf(user))                   //SetMapIndex 往map里添加一个key-value对mapValue.MapIndex(key).Elem().FieldByName("Name").SetString("Tom") //MapIndex 根据Key取出对应的mapuserMap = mapValue.Interface().(map[int]*User)fmt.Printf("user name %s %s\n", userMap[1].Name, user.Name) //user name Tom Tom
}

七、反射调用函数和成员方法

  • 反射调用函数
func Add(a, b int) int {return a + b
}func main() {valueFunc := reflect.ValueOf(Add) //函数也是一种数据类型typeFunc := reflect.TypeOf(Add)argNum := typeFunc.NumIn()            //函数输入参数的个数args := make([]reflect.Value, argNum) //准备函数的输入参数for i := 0; i < argNum; i++ {if typeFunc.In(i).Kind() == reflect.Int {args[i] = reflect.ValueOf(3) //给每一个参数都赋3}}sumValue := valueFunc.Call(args) //返回[]reflect.Value,因为go语言的函数返回可能是一个列表if typeFunc.Out(0).Kind() == reflect.Int {sum := sumValue[0].Interface().(int) //从Value转为原始数据类型fmt.Printf("sum=%d\n", sum)          //sum=6}sumValue = valueFunc.Call([]reflect.Value{reflect.ValueOf(3), reflect.ValueOf(4)})if typeFunc.Out(0).Kind() == reflect.Int {sum := sumValue[0].Interface().(int) //从Value转为原始数据类型fmt.Printf("sum=%d\n", sum)          //sum=7}
}
  • 反射调用成员方法
type User struct {Id     intage    int64Gender bool `json:"sex"`Name   string
}func (u *User) GetAge() int64 {return u.age
}func (u User) Think() {fmt.Printf("%s is in Think\n", u.Name)
}func main() {user := &User{7, 18, false, "jack"}valueUser := reflect.ValueOf(user)               //必须传指针,因为GetAge()在定义的时候它是指针的方法bmiMethod := valueUser.MethodByName("GetAge")    //MethodByName()通过Name返回类的成员变量resultValue := bmiMethod.Call([]reflect.Value{}) //无参数时传一个空的切片result := resultValue[0].Interface().(int64)fmt.Printf("GetAge=%d\n", result) //GetAge=18//Think()在定义的时候用的不是指针,valueUser可以用指针也可以不用指针thinkMethod := valueUser.MethodByName("Think")thinkMethod.Call([]reflect.Value{}) //jack is in ThinkvalueUser2 := reflect.ValueOf(user)thinkMethod = valueUser2.MethodByName("Think")thinkMethod.Call([]reflect.Value{}) //jack is in Think
}

相关文章:

9、面向对象、泛型与反射

目录一、构造函数二、继承与重写三、泛型四、反射1 - 反射的基本概念2 - 反射的基础数据类型3 - 反射APIa - 获取Type类型b - 获取struct成员变量的信息c - 获取struct成员方法的信息d - 获取函数的信息e - 判断类型是否实现了某接口五、reflect.Valuea - 空value判断b - 获取V…...

Python使用百度通用API进行翻译

想汉化StarUML这个软件&#xff0c;感觉工作量太大&#xff0c;想要用Python自动翻译。 结果网上找的一个个用不了&#xff0c;或者用一会儿就断。 于是自己手写了一个简单的&#xff0c;只有两个类&#xff1a;APIConfig和Translater 使用 demo my_api_config APIConfig(…...

JavaScript 弹窗

文章目录JavaScript 弹窗警告框确认框提示框换行JavaScript 弹窗 可以在 JavaScript 中创建三种消息框&#xff1a;警告框、确认框、提示框。 警告框 警告框经常用于确保用户可以得到某些信息。 当警告框出现后&#xff0c;用户需要点击确定按钮才能继续进行操作。 语法 wi…...

408复试day1

文章目录数据结构计算机组成原理操作系统计算机网络数据结构 深度优先遍历DFS&#xff1a; 首先访问图中起始顶点v&#xff0c;然后由v出发&#xff0c;访问与v邻接且未被访问的顶点v1&#xff0c;再访问与v1相邻的且未被访问的顶点v2……重复上述过程。当不能再继续向下访问时…...

gdb openocd jlink arm-a9调试

连接关系是这样的&#xff1a;gdb —> openocd —>&#xff08;这里需要两个xx.cfg配置文件&#xff09; jlink —> arm-a9板子 具体流程是这样的&#xff1a; 给jlink&#xff08;硬件调试器&#xff09;安装驱动&#xff0c;用USB Driver Tool这个软件&#xff0c;…...

Leetcode Solutions - Part 2

1. Two Sum 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按…...

外盘国际期货:围观那些奇葩的国际节日?

围观那些奇葩的国际节日&#xff1f; 2月24日&#xff1a;世界讨厌香菜日&#xff0c;号召全世界所以讨厌香菜的人一起抵制香菜&#xff0c;2016年世界反香菜联盟 3月21日&#xff1a;世界睡眠日&#xff0c;唤起全民对睡眠重要性的认识&#xff0c;2001年国际精神卫生组织 …...

Kubernetes之服务的基本管理

svc是kubernetes最核心的概念&#xff0c;通过创建Service&#xff0c;可以为一组具有相同功能的容器应用提供一个统一的入口地址&#xff0c;并将请求进行负载分发到后端的各个容器应用上。pod生命周期短不稳定&#xff0c;pod异常后新生成的pod的IP会发生变化&#xff0c;通过…...

TimeWheel时间轮算法原理及实现(附源码)

时间轮算法原理及实现前言1.时间轮核心2.简单定时器3.任务队列4.优化任务队列5.简单时间轮6.多层时间轮前言 在各种业务场景中,我们总是会需要一些定时进行一些操作,这些操作可能是需要在指定的某个时间点操作,也可能是每过一个固定的时间间隔后进行操作,这就要求我们需要有一个…...

【蓝牙mesh】Upper协议层介绍

【蓝牙mesh】Upper协议层介绍 Upper层简介 Upper协议层用于处理网络层以上的功能&#xff0c;包括设备的应用层数据、安全、群组等信息&#xff0c;是实现蓝牙mesh应用功能的关键协议之一。Upper层接收来自Access层的数据或者是Upper层自己生成的Control数据&#xff0c;并且将…...

NEXUS 6P刷机安装Edxposed

刷机 abd等工具下载&#xff1a; https://developer.android.com/studio/releases/platform-tools?hlzh-cn 下载后配置环境变量 镜像下载&#xff1a; https://developers.google.com/android/images?hlzh-cn#angler Magisk下载 GitHub - topjohnwu/Magisk: The Magic M…...

web、ES、vue等知识总结

1&#xff1a;Vue2和vue3的区别: 一个、两个2&#xff1a;Vue3.x为什么要用Proxy来代替Object.defineProperty?3&#xff1a;Proxy4&#xff1a;一些知识点的原理全面5&#xff1a;vue3中加入eslint和prettier6&#xff1a;详解vue中的diff算法7:响应式布局的常用解决方案对比…...

数据库第一章(王珊课后习题)

文章目录1.试述数据、数据库、数据库管理系统、数据库系统的概念2.使用数据库系统有什么好处&#xff1f;3.试述文件系统与数据库系统的区别和联系。4.试述数据库系统的特点5.数据库管理系统的主要功能有哪些&#xff1f;6.什么是概念模型?试叙述概念模型的作用7.解释实体、实…...

设计模式(十一)----结构型模式之装饰者模式

1、概述 我们先来看一个快餐店的例子。 快餐店有炒面、炒饭这些快餐&#xff0c;可以额外附加鸡蛋、火腿、培根这些配菜&#xff0c;当然加配菜需要额外加钱&#xff0c;每个配菜的价钱通常不太一样&#xff0c;那么计算总价就会显得比较麻烦。 使用继承的方式存在的问题&…...

lighthouse的介绍和基本使用方法

Lighthouse简介 Lighthouse是一个开源的自动化性能测试工具&#xff0c;我们可以使用该功能检测我们的页面存在那些性能方面的问题&#xff0c;并会生成一个详细的性能报告来帮助我们来优化页面 使用方式 LH一共有四种使用方式 Chrome开发者工具Chrome扩展Node 命令行Node …...

分布式算法 - Raft算法

Paxos是出了名的难懂&#xff0c;而Raft正是为了探索一种更易于理解的一致性算法而产生的。它的首要设计目的就是易于理解&#xff0c;所以在选主的冲突处理等方式上它都选择了非常简单明了的解决方案。推荐阅读提示强烈推荐通过如下资料学习raft。 raft.github.io这里面有一个…...

Python|每日一练|链表|双指针|数组|递归|图算法|单选记录:删除链表的倒数第 N 个结点|下一个排列|迷宫问题

1、删除链表的倒数第 N 个结点&#xff08;链表&#xff0c;双指针&#xff09; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 进阶&#xff1a;你能尝试使用一趟扫描实现吗&#xff1f; 示例 1&#xff1a; 输入&#xff1a;head …...

天线理论知识2——宽带天线介绍

系列文章目录 文章目录 系列文章目录前言一、行波天线1. 长导线天线2. V形天线二、螺旋天线三、八木-宇田天线前言 宽带天线指的是具有哦宽频带特性的天线,常见的宽带天线有行波天线,螺旋天线以及八木天线。 一、行波天线 长度为 l l l的中心馈电的线天线上的电流呈驻波分…...

【计组笔记05】计算机组成与原理之虚拟存储器、指令系统、中央处理器CPU

这篇文章,主要介绍计算机组成与原理之虚拟存储器、指令系统、中央处理器CPU。 目录 一、虚拟存储器 1.1、页式虚拟存储器 1.2、段式虚拟存储器 1...

多功能土壤速测仪功能介绍

大家好&#xff0c;今天给大家介绍一款多功能土壤速测仪&#xff0c;它由多功能速测仪主机、土壤墒情传感器、USB数据线、电源适配器、便携式手提箱等部分组成。速测主机配备有工业级液晶屏&#xff0c;大屏幕中文显示&#xff0c;使得测量参数&#xff0c;时间&#xff0c;设备…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

Go 并发编程基础:通道(Channel)的使用

在 Go 中&#xff0c;Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式&#xff0c;用于在多个 Goroutine 之间传递数据&#xff0c;从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...

认识CMake并使用CMake构建自己的第一个项目

1.CMake的作用和优势 跨平台支持&#xff1a;CMake支持多种操作系统和编译器&#xff0c;使用同一份构建配置可以在不同的环境中使用 简化配置&#xff1a;通过CMakeLists.txt文件&#xff0c;用户可以定义项目结构、依赖项、编译选项等&#xff0c;无需手动编写复杂的构建脚本…...

解析两阶段提交与三阶段提交的核心差异及MySQL实现方案

引言 在分布式系统的事务处理中&#xff0c;如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议&#xff08;2PC&#xff09;通过准备阶段与提交阶段的协调机制&#xff0c;以同步决策模式确保事务原子性。其改进版本三阶段提交协议&#xff08;3PC&#xf…...