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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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 intv.Kind() 与 v.Type() 返回了不同的类型值,Kind() 返回的是 intType() 返回的是 MyInt
在 Go 中,可以用 type 关键字定义自定义类型,Kind() 方法返回底层数据类型,比如这里的 int

比如还有结构体,指针等类型用 type 定义,那么 Kind() 方法就可以获取这些类型的底层类型。

在源码中 Kind() 方法,返回一个常量,如 Uint,Float64,Slice 等等,表示底层数据类型。

 

posted @   codestacklinuxer  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示