存储一组构造函数,用于所有符合相同接口的类型。

huangapple go评论90阅读模式
英文:

Store a collection of constructors for types that all conform to the same interface

问题

我正在制作一个需要一组规则来运行作业的应用程序。该应用程序提供了以几种不同语言表达规则的可能性。因此,我定义了一个与实时规则引擎的接口,该接口提供了应用程序查询当前规则集所需的方法。在这个接口的后面,将会有一个根据源语言不同的引擎类型。

现在,我想根据规则文件的扩展名实例化一个规则引擎。但是我遇到了一些难以克服的错误。

让我首先提供这个简化的框架:

package main

//
//
// The interface

type RulesEngine interface {
    SomeRuleEvaluator(string) bool
}

//
//
// An implementation, with its constructor

type ASimpleRulesEngine struct {
    // I've also tried with :
    // RulesEngine
}

func NewASimpleRulesEngine(context string) *ASimpleRulesEngine {
    re := ASimpleRulesEngine{}
    return &re
}

func (re *ASimpleRulesEngine) SomeRuleEvaluator(dummy string) bool {
    return true
}

//
//
// A client, that'll want to be able to choose a constructor

var rulesEngineConstructorsPerExtension map[string](func(string) RulesEngine)

func init() {
    rulesEngineConstructorsPerExtension = make(map[string](func(string)RulesEngine))
    rulesEngineConstructorsPerExtension[".ini"] = NewASimpleRulesEngine
}

func main() {
}

当我尝试构建这个代码时,我得到了35: cannot use NewASimpleRulesEngine (type func(string) *ASimpleRulesEngine) as type func(string) RulesEngine in assignment的错误。

我还尝试过:

  • 不使用指针进行赋值,尽管在尝试时感觉很愚蠢
  • init函数中使用中间步骤,创建一个new(func (string) RulesEngine),然后进行赋值,有时使用指针,有时不使用指针。
  • 像在C语言中一样存储函数指针,但编译器说它无法获取我的函数的地址。

我对Go不是很熟悉,这感觉有点令人惊讶。应该使用什么样的正确类型签名?这种情况是否可能?如果不可避免,我显然会在一边使用一个简单的扩展名数组(用于检查文件是否可能是规则文件),在另一边使用一个大的switch来提供适当的构造函数,但尽可能避免这种重复。

谢谢您的任何见解!

英文:

I'm making an app that'll need sets of rules to run a job. The app offers the possibility to express the rules in one of several different languages. I therefore have defined an interface to a live rules engine, that offers the methods that the app will need to query the current set of rules. Behind this interface, there will be one different type of engine, according to the source language.

Now I'd like to instantiate a rules engine according to the rule file's extension. But I get some errors which I have a hard time to overcome.

Let me first offer this simplified skeleton :

package main

//
//
// The interface

type RulesEngine interface {
	SomeRuleEvaluator(string) bool
}

//
//
// An implementation, with its constructor

type ASimpleRulesEngine struct {
	// I've also tried with :
	// RulesEngine
}

func NewASimpleRulesEngine(context string) *ASimpleRulesEngine {
	re := ASimpleRulesEngine{}
	return &re
}

func (re *ASimpleRulesEngine) SomeRuleEvaluator(dummy string) bool {
	return true
}

//
//
// A client, that'll want to be able to choose a constructor

var rulesEngineConstructorsPerExtension map[string](func(string) RulesEngine)

func init() {
    rulesEngineConstructorsPerExtension = make(map[string](func(string)RulesEngine))
	rulesEngineConstructorsPerExtension[".ini"] = NewASimpleRulesEngine
}

func main() {
}

When I try to build this, I get 35: cannot use NewASimpleRulesEngine (type func(string) *ASimpleRulesEngine) as type func(string) RulesEngine in assignment

I've also tried :

  • assigning without a pointer, although I felt stupid while trying it
  • having an intermediate step in the initfunction, where I'd create a new(func (string) RulesEngine) and then assign to it, with and without pointer.
  • storing function pointers like in C, but the compiler said it could not take the adress of my function.

I'm not that familiar with Go and this felt a bit surprising. What would be the proper type signature to use ? Is this possible at all ? If it's unavoidable, I'll obviously have a simple array of extensions on one side (to check if a file is potentially a rules file), and a big switch on the other side to provide the adequate constructor, but as much possible I'd like to avoid such duplication.

Thank you for any insight !

答案1

得分: 0

根据@JorgeMarey的评论,并且不想牺牲构造函数的类型签名,我想出了以下解决方案。但是,我觉得这种方法很笨拙。我很乐意听到更简洁的方法。

func init() {
    rulesEngineConstructorsPerExtension = make(map[string](func(string)RulesEngine))

    cast_NewASimpleRulesEngine := func(content string) RulesEngine {
        return NewASimpleRulesEngine(content)
    }

    rulesEngineConstructorsPerExtension[".ini"] = cast_NewASimpleRulesEngine
}

(尝试使用(func(string)RulesEngine)(NewASimpleRulesEngine)进行显式转换也被编译器认为不合适)

英文:

(edited : I've accepted my own answer for lack of any other, but its most relevant part is @seh 's comment below)


Following @JorgeMarey 's comment, and not wanting to sacrifice the constructor's type signature, I came up with this. But it does feel very tacky to me. I'll be glad to hear about a cleaner way.

func init() {
    rulesEngineConstructorsPerExtension = make(map[string](func(string)RulesEngine))

	cast_NewASimpleRulesEngine := func(content string) RulesEngine {
	    return NewASimpleRulesEngine(content)
    }

	rulesEngineConstructorsPerExtension[".ini"] = cast_NewASimpleRulesEngine
}

(an attempt to explicitly cast with (func(string)RulesEngine)( NewASimpleRulesEngine) was deemed unfit by the compiler too)

huangapple
  • 本文由 发表于 2016年12月11日 01:20:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/41078189.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定