【问题标题】:How can I store types in go maps for initialisation at a later stage如何将类型存储在 go 地图中以供稍后进行初始化
【发布时间】:2015-07-17 21:08:44
【问题描述】:

我正在尝试实现一个工厂函数,该函数将返回满足接口 X 契约的众多结构之一的实例。

m := make(map[string] ?)
func init () {
    m["a"] = ?
    m["b"] = ?
}

type X interface { 
    y()
}

type A struct {}
func (a * A) y () {}

type B struct {}
func (b * B) y () {}


function factory(name string) X {
    return &m[name]{}
}

上面的代码只是我要实现的目标的简化演示 - 寻找是否可行的指针,或者是否有不同的 go 习惯用法来解决我缺少的这种要求。

【问题讨论】:

    标签: go


    【解决方案1】:

    如果您有一个简单的值类型,那么正如@VonC 所说,您可以使用map[string]X 并返回示例值的副本。

    对于其他任何事情,我不使用反射,而是使用创建函数的映射。就像image 包的作用一样 image.RegisterFormat.

    例如(playground):

    package main
    
    import "fmt"
    
    type X interface {
            y()
    }
    
    type newXFunc func() X
    
    // Here just a map variable and two functions, but
    // this could be a type with two methods instead.
    
    var m = map[string]newXFunc{}
    
    func register(name string, fn newXFunc) {
            m[name] = fn
    }
    
    func factory(name string) X {
            return m[name]()
    }
    
    func init() {
            // If register is exported than these
            // calls can be in other packages that
            // implement A and B.
            register("a", NewA)
            // For simple things that don't have/need
            // their own stand-alone "new" function.
            register("b", func() X { return B{} })
    }
    
    type A struct{}
    
    func (a *A) y() {}
    func NewA() X   { return &A{} }
    
    type B struct{}
    
    func (b B) y() {}
    
    func main() {
            a1 := factory("a")
            b1 := factory("b")
            fmt.Printf("%T\n", a1)
            fmt.Printf("%T\n", b1)
    }
    

    【讨论】:

    • 功能图比我的回答更有效。 +1
    【解决方案2】:

    您可以使用map[string]X,与 X 接口(可以引用任何遵守 X 合约的对象的值或指针)

    或者是否有不同的 go 习惯用法来解决我缺少的这种需求?

    您也可以使用反射(如“Instance new Type”)来实现您的工厂。

    reflect.New(yourtype).Elem().Interface()
    

    您可以在“is there a way to create an instance of a struct from a string?”中查看工厂示例。


    工厂方法(每次返回一个新实例)的更快方法是使用开关(如in this example):

    // Create a new Widget interface based on WidgetType and set WidgetInfo
    func New(wt WidgetType, wi WidgetInfo) Widget_iface {
        switch wt {
        case Widget_A:
            return newWidgetA(wi)
        case Widget_B:
            return newWidgetB(wi)
        }
        return nil
    } 
    

    【讨论】:

    • 感谢@VonC。看起来使用实例注册类型的额外开销很小,但我猜该实例会很快被垃圾收集?
    • @Ali-AkberSaifee 是的,它会的。但总的来说反射速度较慢,因此如果您打算每秒调用工厂数百次,则映射更快。
    • @Ali-AkberSaifee 您希望您的工厂返回 A 或 B 的 new 实例吗?如果是,我已经编辑了答案。
    • 对于我当前的用例,我只需要一个新实例就可以了 - 但就尝试理解语言而言,我很好奇我是否可以只返回类型
    猜你喜欢
    • 2017-08-24
    • 2019-06-05
    • 2012-07-10
    • 2020-07-10
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多