dongruolin5324 2012-06-20 20:32
浏览 176
已采纳

在Go中基于字符串动态创建某些类型的变量

Simple version
How can you create a variable of a certain type based upon the value of a string?

type ta struct { a int }
type tb struct { b float }
type tc struct { c string }

t := "tb"
v := MagicVarFunc(t) // Returns a new allocated var of type interface{}
v.(tb).b = 8.3

The true example
In my, surprisingly enough, working example below, I am dynamically creating variables based on a string. This is done by registering each struct type in a map with the string being the key and a nil-pointer of the type being the value.
Each type implements an interface with the method New() which returns a new variable of that specific type.

The example below is very close to what I wish to do, where each action has a set of JSON encoded data which will populate the corresponding struct. The way I've structured it is also because I wish to be able to create new stand alone actions that I register to the map.

I am not sure if am abusing the language now.
May anyone give me any pointers if I am completely out of my mind? Is there an obviously easier way?

package main

import (
    "fmt"
    "encoding/json"
)

// All I require of an action is that it may be executed
type ActionHandler interface {
    Exec()
    New() ActionHandler
}

// My list of actions
var mActions = make(map[string]ActionHandler)

// Action Exit (leaving the program)
type aExit struct {}
func (s *aExit) Exec() { fmt.Println("Good bye") }
func (s *aExit) New() ActionHandler { return new(aExit) }
func init() {
    var a *aExit
    mActions[`exit`] = a
}

// Action Say (say a message to someone)
type aSay struct {
    To  string
    Msg string
}
func (s *aSay) Exec() { fmt.Println(`You say, "` + s.Msg + `" to ` + s.To) }
func (s *aSay) New() ActionHandler { return new(aSay) }
func init() {
    var a *aSay
    mActions[`say`] = a
}

func inHandler(action string, data []byte) {
    a := mActions[action].New()
    json.Unmarshal(data, &a)
    a.Exec()
}

func main(){
    inHandler(`say`, []byte(`{"to":"Sonia","msg":"Please help me!"}`))
    inHandler(`exit`, []byte(`{}`))
}
  • 写回答

3条回答 默认 最新

  • doupao6011 2012-06-21 01:56
    关注

    You can use reflection to get the zero value of, or to allocate a new value (like new) of a type using reflection, if you can get the Type value at runtime. However, I don't think there is a way to get the Type from a string. You would need to have a value of that type to get the type itself.

    I adopted your idea, of using a map. I map the string to the type itself, which you can get using reflect.TypeOf, which gets the type out of an interface value. Then I used reflect.Zero to get the zero value of that type (a convenient value that exists for every type). Then I got the value out as an interface.

    package main
    import "reflect"
    
    type ta struct { a int }
    type tb struct { b float64 }
    type tc struct { c string }
    
    var mActions map[string]reflect.Type = make(map[string]reflect.Type)
    func init() {
      var a ta
      mActions[`ta`] = reflect.TypeOf(a)
      var b tb
      mActions[`tb`] = reflect.TypeOf(b)
      var c ta
      mActions[`tc`] = reflect.TypeOf(c)
    }
    
    func MagicVarFunc(action string) interface{} {
      return reflect.Zero(mActions[action]).Interface()
    }
    
    func main() {
      t := "tb"
      v := MagicVarFunc(t) // Returns a new allocated var of type interface{}
      x := v.(tb)
      x.b = 8.3
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 乘性高斯噪声在深度学习网络中的应用
  • ¥15 运筹学排序问题中的在线排序
  • ¥15 关于docker部署flink集成hadoop的yarn,请教个问题 flink启动yarn-session.sh连不上hadoop,这个整了好几天一直不行,求帮忙看一下怎么解决
  • ¥30 求一段fortran代码用IVF编译运行的结果
  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥30 python代码,帮调试,帮帮忙吧