0%

go 通过字符串访问结构体

在使用 orm 操作数据的过程中,gorm 使用 struct 对数据库中的表进行定位。虽然虽然可以 一个表定义一套 增删查改 但是感觉需要的代码量比较多。所以我决定通过字符串访问结构体已应对简单的 增删查改。

这里简单的介绍一下原理新建一个 map ,key 为我们使用的字符串 value 为反射类型,在使用的时候从 map 中取出值,然后通过反射新建出需要使用的类型

这里我先简单声明一下,然后在对它进行封装,以方便我们之后的使用

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

type Test struct { // 我们需要使用到的结构体
    Name string `json:"name"`
}

func main() {
    temp := make(map[string]reflect.Type) // 建立一个类似于模板仓库的东西

    temp["test"] = reflect.TypeOf(Test{}) // 将类型转换成反射类型在需要使用的时候通过反射新建对应实例

    // 上面是如何存储
    //-----------------------
    // 接下来就是如何取出来了
    t, ok := temp["test"] // 检查元素是否真实存在
    if !ok {
        panic("test 结构体未进行储存") // 这里只是演示实际处理根据你的真实使用情况来定
    }

    fmt.Printf("%T\n", t) // 检查一下类型司机上并没有哦什么用

    // 通过反射新建实例并转成 interface 别问我为什么这样写 如果放进去的是一个 对应类型的 interface 再反射出来使用,在第二次使用时携带上一次的值(不是本次使用的方式)
    foo := reflect.New(t).Interface() // 类似于 new(type) 因为下一步会使用反射将值放进去
    fmt.Printf("%T\n", foo)           // 检测一下即将使用的类型

    // 类型新建好后对它进行赋值

    // 使用 json 解析将值放进去当然你也可以使用反射 不过我觉得这种方式更简单
    m := map[string]interface{}{"name": "niconiconi"}
    res, err := json.Marshal(m)
    if err != nil {
        panic(err)
    }
    if err := json.Unmarshal(res, foo); err != nil {
        panic(err)
    }

    fmt.Printf("type == %T | value == %v\n", foo, foo) // 检测一下类型以及值

    // 到这里就结束了
}

在上面了例子中演示了,如何通过 string 访问 struct 当然在实际使用中是可能会有多个 model 需要使用我们都把它塞进 map 就好了。

为了方便使用我们可以对上面的例子加一点点细节,类似于下面这样

// 在使用之前 调用 New 函数新建工厂
// Add 方法 放入你需要的类型
// Get("typeName") 获取你需要的类型

package factory

import (
    "fmt"
    "reflect"
    "strings"
)

// Store 模板实体
type Store struct {
    temp map[string]reflect.Type
}

// Add 添加(需要 非指针)
func (m *Store) Add(in ...interface{}) {
    if m.temp == nil {
        m.temp = make(map[string]reflect.Type)
    }

    for _, v := range in {
        refType := reflect.TypeOf(v)
        split := strings.Split(refType.String(), ".")
        name := strings.ToLower(split[len(split)-1])

        m.temp[name] = refType
    }
}

// Get 获取一个新的模板(指针类型)
func (m Store) Get(name string) (interface{}, error) {
    layout, ok := m.temp[name]
    if !ok {
        return nil, fmt.Errorf("%s does not exist", name)
    }

    temp := reflect.New(layout).Interface()
    return temp, nil
}

// New 新建
func New() Store {
    return Store{}
}

使用方式类似于下面这样,注意不是真实代码

package main

var prop = factory.New()
func init()  {
    prop.Add(user{}, file{})
}

func foo() (interface{}, int46 ,error) {
    tableS := "user" // 外部获取
    rows, err := prop.Get(tableS)
    if err != nil{
        return, 0, err
    }

    // 然后使用上面例子中 json 的方式放进去 或者 给其他 组件使用

    //err = db.X().Model(local).Where(kvs).Count(&total).Order(sort).Offset((pi - 1) * ps).Limit(ps).Find(rows).Error
    //return rows, total, err
}

在这里提供一个 gorm 的查询思路 表 从 uri 中获取 查询条件 使用 url ? 后面的 字符串(也叫查询条件)并将其转换成 map 塞进 gorm 的查询条件结果映射回我们 上面封装的方法获取的模板。

需要一个 我们就放一个 struct 需要 []struct 那就放 []struct 进去 全程不需要一条 SQL 语句 真香。

最后祝你玩得开心 (*^_^*)