前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >go语言:反射,用字符串调用函数创建结构

go语言:反射,用字符串调用函数创建结构

作者头像
超级大猪
发布2019-11-22 09:44:28
3.2K0
发布2019-11-22 09:44:28
举报
文章被收录于专栏:大猪的笔记

go语言可以通过反射来进行函数调用和类的创建,但是go中没有类型工厂,所以在使用前要“丑陋”的先把类型注册一下。 相关示例代码如下(未容错,仅做为示例,不能直接用于产品): 先看用法,免得被吓跑

代码语言:javascript
复制
package main

import (
    "fmt"
    "utils/typefac"
)

//测试调用
func main() {
    // 测试创建对象
    typefac.RegisterType(HuaweiSchool{})
    classinfo := "main.HuaweiSchool"

    in := make(map[string]interface{})
    in["Name"] = &StcName{"Euler1"}
    in["Id"] = 111
    school := typefac.CreateInstance(classinfo, in).(School)
    fmt.Println(school)
    school.PrintName()

    school.SetID(222)
    school.PrintName()

    // 测试调用函数
    typefac.RegFunc("NewHuaweiSchool", NewHuaweiSchool)

    v, _ := typefac.Run("NewHuaweiSchool", "Euler2", 123)
    school = v[0].Interface().(*HuaweiSchool)
    school.PrintName()
}

type School interface {
    PrintName()
    SetID(int)
}

type HuaweiSchool struct {
    Name *StcName
    Id   int
}

func (s HuaweiSchool) PrintName() {
    fmt.Println("welcome to huawei", s.Name, " school, id:", s.Id)
}

func (s *HuaweiSchool) SetID(id int) {
    s.Id = id
}

type StcName struct {
    Name string
}

func NewHuaweiSchool(name string, id int) *HuaweiSchool {
    m := new(HuaweiSchool)
    m.Name = &StcName{name}
    m.Id = id
    return m
}

相关库

代码语言:javascript
复制
package typefac

import (
    "errors"
    "reflect"
)

var funcMap = make(map[string]interface{})

// RegFunc 注册一个函数
// typefac.RegFunc("NewHuaweiSchool", NewHuaweiSchool)
func RegFunc(name string, fc interface{}) {
    funcMap[name] = fc
}

// Run 运行被注册的函数
// usage: v, _ := typefac.Run("NewHuaweiSchool", "Euler2", 123)
// school = v[0].Interface().(*HuaweiSchool)
func Run(name string, params ...interface{}) (result []reflect.Value, err error) {
    if _, ok := funcMap[name]; !ok {
        err = errors.New(name + " does not exist.")
        return
    }
    f := reflect.ValueOf(funcMap[name])
    if len(params) != f.Type().NumIn() {
        err = errors.New("The number of params is not adapted")
        return
    }
    in := make([]reflect.Value, len(params))
    for k, param := range params {
        in[k] = reflect.ValueOf(param)
    }
    result = f.Call(in)
    return
}

var typeRegistry = make(map[string]reflect.Type)

// RegisterType 注册类型
func RegisterType(typedNil interface{}) {
    t := reflect.TypeOf(typedNil)
    typeRegistry[t.PkgPath()+"."+t.Name()] = t
}

// CreateInstance 传入被注册的类型和初值,创建一个对象
// usage: in := make(map[string]interface{})
// in["Name"] = StcName{"Euler1"}
// in["Id"] = 111
// school := typefac.CreateInstance(classinfo, in).(School)
func CreateInstance(name string, input map[string]interface{}) interface{} {
    structObj := reflect.New(typeRegistry[name])
    structObjValue := structObj.Elem()
    for attrname, attrvalue := range input {
        // structObjValue.FieldByName(attrname).Set(reflect.ValueOf(attrvalue))
        assign(structObjValue.FieldByName(attrname), attrvalue)

    }
    return structObj.Interface()
}

func assign(v reflect.Value, input interface{}) {
    iv := reflect.ValueOf(input)
    if v.CanSet() {
        switch v.Kind() {
        case reflect.Bool:
            v.SetBool(iv.Bool())
        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
            v.SetInt(iv.Int())
        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
            v.SetUint(iv.Uint())
        case reflect.String:
            v.SetString(iv.String())
        case reflect.Slice: //TODO...
        case reflect.Map: //TODO...
        case reflect.Struct:
            for i := 0; i < v.NumField(); i++ {
                structAttr := v.Field(i)
                if structAttr.IsValid() == false || structAttr.CanSet() == false {
                    continue
                }
                assign(structAttr, iv.Field(i).Interface())
            }
        case reflect.Ptr:
            v.Set(iv)
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-11-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档