2016-12-10 11 views
0

Я создаю приложение, которое будет нуждаться в наборах правил для запуска задания. Приложение предлагает возможность выражения правил на одном из нескольких языков. Поэтому я определил интерфейс к движку живых правил, который предлагает методы, которые приложение должно будет запрашивать для текущего набора правил. Позади этого интерфейса, в зависимости от исходного языка, будет один тип движка.Храните коллекцию конструкторов для типов, все из которых соответствуют одному и тому же интерфейсу.

Теперь я хотел бы создать экземпляр механизма правил в соответствии с расширением файла правила. Но я получаю некоторые ошибки, которые мне трудно преодолеть.

Позвольте мне первым предложить этот упрощенный скелет:

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 ion, где я бы создал new(func (string) RulesEngine), а затем назначил ему, с указателем и без него.
  • Сохранение указателей функций, таких как C, но компилятор сказал, что не может принять адрес моей функции.

Я не знаком с Go, и это было немного удивительно. Какая должна быть правильная подпись типа? Это вообще возможно ? Если это неизбежно, у меня, очевидно, будет простой массив расширений с одной стороны (чтобы проверить, является ли файл потенциально файлом правил) и большой switch с другой стороны, чтобы предоставить соответствующий конструктор, но насколько это возможно, d избегать такого дублирования.

Благодарим за понимание!

+1

Попробуйте изменить тип возвращаемого NewASimpleRulesEngine к RulesEngine –

+0

Спасибо, он сделал работу, хотя он действительно чувствует себя немного неудовлетворительным. Теперь мои объекты не могут легко реализовать несколько интерфейсов, не так ли? –

ответ

0

(под редакцией: Я принял свой собственный ответ на отсутствие какой-либо другой, но его релевантность часть «s комментарий ниже


После @JorgeMarey @seh)» комментарий с, и не желая чтобы жертвовать сигнатурой типа конструктора, я придумал это. Но он чувствует себя очень липким для меня. Я буду рад узнать о более чистом пути.

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) был признан непригодным компилятором тоже)

+1

Go не имеет ковариантных типов возврата в соответствии с следующим пунктом часто задаваемых вопросов: https://golang.org/doc/faq#covariant_types. На мой взгляд, это не столько объяснение * почему *, сколько подтверждение предполагаемого недостатка. И это не дает намека на то, как получить то, что вы хотите. Вместо этого он говорит вам не хотеть этого. – seh