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
:Name
represents 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
:PkgPath
represents 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
PkgPath
field will be an empty string. - If the field type is defined in an imported package, the
PkgPath
field will contain the import path of that package.
-
Type
:Type
represents 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
:Tag
represents 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
:Offset
represents 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
:Index
represents 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
:Anonymous
is 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的胖子
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南