gout 使用 笔记1
断言
// 目的是检查 *QueryEncode 类型是否满足了 Adder 接口。 // 在这里,Adder 是一个接口类型,QueryEncode 是一个具体的类型。QueryEncode 类型是否实现了add 接口 var _ Adder = (*QueryEncode)(nil)
反射
x := 42 p := reflect.ValueOf(&x) // 使用反射获取 x 的地址,并将其封装成 reflect.Value 类型的值 for p.Kind() == reflect.Ptr { p = p.Elem() // 解引用指针,获取 x 的值的 reflect.Value } fmt.Println(p.Interface()) // 输出: 42
func GetString(v interface{}) (s string, ok bool) { switch s := v.(type) { case []byte: return BytesToString(s), true case string: return s, true } return "", false } func isAndGetString(x interface{}) (string, bool) { p := reflect.ValueOf(x) for p.Kind() == reflect.Ptr { p = p.Elem() } if s, ok := core.GetString(p.Interface()); ok { return strings.TrimPrefix(s, "?"), true } return "", false }
// Encode core entry function // in 的类型可以是 // struct // map // []string func Encode(in interface{}, a Adder) error { v := reflect.ValueOf(in) for v.Kind() == reflect.Ptr { if v.IsNil() { return nil } v = v.Elem() } switch v.Kind() { case reflect.Map: iter := v.MapRange() for iter.Next() { keyName := valToStr(iter.Key(), emptyField) if err := setMoreTypes(iter.Value(), emptyField, a, keyName); err != nil { return err } } return nil case reflect.Struct: if err := encode(v, emptyField, a); err != nil { return err } return nil case reflect.Slice, reflect.Array: if v.Len() == 0 { return nil } if v.Len()%2 != 0 { return fmt.Errorf("The %T length of the code must be even", v.Kind()) } for i, l := 0, v.Len(); i < l; i += 2 { keyName := valToStr(v.Index(i), emptyField) if err := setMoreTypes(v.Index(i+1), emptyField, a, keyName); err != nil { return err } } return nil } return ErrUnsupported }
此时需要关注各种map struct 反射!!!!
参考反射库文章
反射的使用
- reflect包封装了反射相关的方法
- 获取类型信息:reflect.TypeOf,是静态的
- 获取值信息:reflect.ValueOf,是动态的
空接口与反射
- 反射可以在运行时动态获取程序的各种详细信息
- 反射获取interface类型信息
package main import ( "fmt" "reflect" ) //反射获取interface类型信息 func reflect_type(a interface{}) { t := reflect.TypeOf(a) fmt.Println("类型是:", t) // kind()可以获取具体类型 k := t.Kind() fmt.Println(k) switch k { case reflect.Float64: fmt.Printf("a is float64\n") case reflect.String: fmt.Println("string") } v := reflect.ValueOf(a) fmt.Println(v) } func main() { var x float64 = 3.4 reflect_type(x) }
- 反射修改值信息
package main import ( "fmt" "reflect" ) //反射修改值 func reflect_set_value(a interface{}) { v := reflect.ValueOf(a) k := v.Kind() switch k { case reflect.Float64: // 反射修改值 v.SetFloat(6.9) fmt.Println("a is ", v.Float()) case reflect.Ptr: // Elem()获取地址指向的值 v.Elem().SetFloat(7.9) fmt.Println("case:", v.Elem().Float()) // 地址 fmt.Println(v.Pointer()) } } func main() { var x float64 = 3.4 // 反射认为下面是指针类型,不是float类型 reflect_set_value(&x) fmt.Println("main:", x) }
结构体与反射
查看类型、字段和方法
package main import ( "fmt" "reflect" ) // 定义结构体 type User struct { Id int Name string Age int } // 绑方法 func (u User) Hello() { fmt.Println("Hello") } // 传入interface{} func Poni(o interface{}) { t := reflect.TypeOf(o) fmt.Println("类型:", t) fmt.Println("字符串类型:", t.Name()) // 获取值 v := reflect.ValueOf(o) fmt.Println("value:", v) k := v.Kind() fmt.Println("Kind:", k) fmt.Println("type:", v.Type()) // 可以获取所有属性 // 获取结构体字段个数:t.NumField() for i := 0; i < t.NumField(); i++ { // 取每个字段 f := t.Field(i) fmt.Printf("%s : %v ", f.Name, f.Type) // 获取字段的值信息 // Interface():获取字段对应的值 val := v.Field(i).Interface() fmt.Println("val :", val) } fmt.Println("=================方法====================") for i := 0; i < t.NumMethod(); i++ { m := t.Method(i) fmt.Println(m.Name) fmt.Println(m.Type) } } func main() { u := User{1, "zs", 20} Poni(u) } /* 运行结果 PC端 类型: main.User 字符串类型: User value: {1 zs 20} Kind: struct type: main.User Id : int --val : 1 Name : string --val : zs Age : int --val : 20 =================方法==================== Hello func(main.User) */
查看匿名字段
package main import ( "fmt" "reflect" ) // 定义结构体 type User struct { Id int Name string Age int } // 匿名字段 type Boy struct { User Addr string } func main() { m := Boy{User{1, "zs", 20}, "bj"} t := reflect.TypeOf(m) fmt.Println(t) sf := t.Field(0) // Anonymous:匿名 fmt.Printf("%#v \n %v \n", t.Field(0), sf.Anonymous) sf = t.Field(1) // Anonymous:匿名 fmt.Printf("%#v \n %v \n", t.Field(1), sf.Anonymous) // 值信息 fmt.Printf("%#v\n", reflect.ValueOf(m).Field(0)) } /* main.Boy reflect.StructField{Name:"User", PkgPath:"", Type:(*reflect.rtype)(0x497980), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true} true reflect.StructField{Name:"Addr", PkgPath:"", Type:(*reflect.rtype)(0x48be00), Tag:"", Offset:0x20, Index:[]int{1}, Anonymous:false} false main.User{Id:1, Name:"zs", Age:20} */
PkgPath 表示什么?
Let's clarify the actual fields in the reflect.StructField struct and their meanings:
- 
Name:- Namerepresents the name of the struct field.
- It is a string that holds the name of the field as it appears in the struct definition.
 
- 
PkgPath:- PkgPathrepresents the package path of the field type. It contains the import path of the package where the field's type is defined.
- If the field type is defined in the same package where the struct is declared, the PkgPathfield will be an empty string.
- If the field type is defined in an imported package, the PkgPathfield will contain the import path of that package.
 
- 
Type:- Typerepresents the type of the field.
- It is a reflect.Type(or*reflect.rtype) that provides information about the field's data type, such as the name, kind, and methods associated with the type.
 
- 
Tag:- Tagrepresents the tag string associated with the field. Tags are arbitrary metadata that can be associated with struct fields and are often used for serialization/deserialization or other purposes.
- Tags are specified in the struct field definition using backticks (``).
- Tags are typically used to provide additional information about the field, such as JSON or XML tags for serialization or validation rules.
 
- 
Offset:- Offsetrepresents the offset of the field in the struct's memory layout.
- It indicates the number of bytes from the beginning of the struct to the start of the field.
 
- 
Index:- Indexrepresents the index sequence of the field in a nested struct. It is used when the field is part of a nested struct, and it indicates the index path to reach the field in the nested struct.
 
- 
Anonymous:- Anonymousis a boolean value that indicates whether the struct field is an anonymous field.
- An anonymous field is a field that has no name and is embedded directly within the struct without a field name.
- When a struct field is anonymous, it effectively "inherits" all the fields and methods of the embedded struct, and you can access them as if they were part of the outer struct directly.
 
修改结构体的值
package main import ( "fmt" "reflect" ) // 定义结构体 type User struct { Id int Name string Age int } // 修改结构体值 func SetValue(o interface{}) { v := reflect.ValueOf(o) // 获取指针指向的元素 v = v.Elem() // 取字段 f := v.FieldByName("Name") if f.Kind() == reflect.String { f.SetString("kuteng") } } func main() { u := User{1, "5lmh.com", 20} SetValue(&u) fmt.Println(u) }
获取字段的tag
package main import ( "fmt" "reflect" ) type Student struct { Name string `json:"name1" db:"name2"` } func main() { var s Student v := reflect.ValueOf(&s) fmt.Printf("%#v\n", v) // 类型 t := v.Type() fmt.Printf("%#v\n", t) // 获取字段 f := t.Elem().Field(0) fmt.Printf("%#v\n", f) fmt.Println(f.Tag.Get("json")) fmt.Println(f.Tag.Get("db")) } /* &main.Student{Name:""} &reflect.rtype{size:0x8, ptrdata:0x8, hash:0x1279310c, tflag:0x0, align:0x8, fieldAlign:0x8, kind:0x36, alg:(*reflect.typeAlg)(0x4fc990), gcdata:(*uint8)(0x4b0dab), str:18560, ptrToThis:0} reflect.StructField{Name:"Name", PkgPath:"", Type:(*reflect.rtype)(0x48cd20), Tag:"json:\"name1\" db:\"name2\"", Offset:0x0, Index:[]int{0}, Anonymous:false} name1 name2 */
package encode import ( "errors" "fmt" "reflect" "strconv" "strings" "time" "unsafe" "github.com/guonaihong/gout/core" ) // ErrUnsupported Unsupported type error returned var ErrUnsupported = errors.New("Encode:Unsupported type") var emptyField = reflect.StructField{} // Adder interface type Adder interface { Add(key string, v reflect.Value, sf reflect.StructField) error Name() string } // Encode core entry function // in 的类型可以是 // struct // map // []string func Encode(in interface{}, a Adder) error { v := reflect.ValueOf(in) for v.Kind() == reflect.Ptr { if v.IsNil() { return nil } v = v.Elem() } switch v.Kind() { case reflect.Map: iter := v.MapRange() for iter.Next() { keyName := valToStr(iter.Key(), emptyField) if err := setMoreTypes(iter.Value(), emptyField, a, keyName); err != nil { return err } } return nil case reflect.Struct: if err := encode(v, emptyField, a); err != nil { return err } return nil case reflect.Slice, reflect.Array: if v.Len() == 0 { return nil } if v.Len()%2 != 0 { return fmt.Errorf("The %T length of the code must be even", v.Kind()) } for i, l := 0, v.Len(); i < l; i += 2 { keyName := valToStr(v.Index(i), emptyField) if err := setMoreTypes(v.Index(i+1), emptyField, a, keyName); err != nil { return err } } return nil } return ErrUnsupported } func parseTag(tag string) (string, tagOptions) { s := strings.Split(tag, ",") return s[0], s[1:] } func timeToStr(v reflect.Value, sf reflect.StructField) string { t := v.Interface().(time.Time) if t.IsZero() { return "" } timeFormat := sf.Tag.Get("time_format") if timeFormat == "" { timeFormat = time.RFC3339 } switch tf := strings.ToLower(timeFormat); tf { case "unix", "unixnano": var tv int64 if tf == "unix" { tv = t.Unix() } else { tv = t.UnixNano() } return strconv.FormatInt(tv, 10) } return t.Format(timeFormat) } func valToStr(v reflect.Value, sf reflect.StructField) string { for v.Kind() == reflect.Ptr { if v.IsNil() { return "" } v = v.Elem() } if v.Type() == timeType { return timeToStr(v, sf) } // 看: // https://github.com/guonaihong/gout/issues/322 /* if v.IsZero() { return "" } */ if b, ok := v.Interface().([]byte); ok { return *(*string)(unsafe.Pointer(&b)) } return fmt.Sprint(v.Interface()) } func setMoreTypes(val reflect.Value, sf reflect.StructField, a Adder, tagName string) error { switch val.Interface().(type) { case string, []byte, core.FormMem, core.FormFile: default: if val.Kind() == reflect.Interface { val = val.Elem() } switch val.Kind() { case reflect.Slice, reflect.Array: for i, l := 0, val.Len(); i < l; i++ { if err := a.Add(tagName, val.Index(i), sf); err != nil { return err } } return nil } } return a.Add(tagName, val, sf) } func parseTagAndSet(val reflect.Value, sf reflect.StructField, a Adder) error { tagName := sf.Tag.Get(a.Name()) tagName, opts := parseTag(tagName) if tagName == "" { tagName = sf.Name } if tagName == "" { return nil } if opts.Contains("omitempty") && valueIsEmpty(val) { return nil } return setMoreTypes(val, sf, a, tagName) } func encode(val reflect.Value, sf reflect.StructField, a Adder) error { vKind := val.Kind() if val.Kind() == reflect.Ptr { if val.IsNil() { return nil } return encode(val.Elem(), sf, a) } if vKind != reflect.Struct || !sf.Anonymous { if err := parseTagAndSet(val, sf, a); err != nil { return err } } if vKind == reflect.Struct { typ := val.Type() // TODO使用接口解耦具体类型 if strings.HasSuffix(typ.Name(), "FormType") { return parseTagAndSet(val, sf, a) } for i := 0; i < typ.NumField(); i++ { sf := typ.Field(i) if sf.PkgPath != "" && !sf.Anonymous { continue } tag := sf.Tag.Get(a.Name()) if tag == "-" { continue } if err := encode(val.Field(i), sf, a); err != nil { return err } } } return nil } type tagOptions []string func (t tagOptions) Contains(tag string) bool { for _, v := range t { if tag == v { return true } } return false } var timeType = reflect.TypeOf(time.Time{}) func valueIsEmpty(v reflect.Value) bool { switch v.Kind() { case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Slice, reflect.Array, reflect.Map, reflect.String: return v.Len() == 0 case reflect.Bool: return !v.Bool() case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Interface, reflect.Ptr: return v.IsNil() case reflect.Invalid: return true } if v.Type() == timeType { return v.Interface().(time.Time).IsZero() } return false }
如定义 type MyInt int,v.Kind() 与 v.Type() 返回了不同的类型值,Kind() 返回的是 int,Type() 返回的是 MyInt。
在 Go 中,可以用 type 关键字定义自定义类型,Kind() 方法返回底层数据类型,比如这里的 int。
比如还有结构体,指针等类型用 type 定义,那么 Kind() 方法就可以获取这些类型的底层类型。
在源码中 Kind() 方法,返回一个常量,如 Uint,Float64,Slice 等等,表示底层数据类型。
    http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!!
但行好事 莫问前程
--身高体重180的胖子
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号