Храните коллекцию конструкторов для типов, которые все соответствуют одному и тому же интерфейсу
Я делаю приложение, которое будет нуждаться в наборах правил для выполнения работы. Приложение предлагает возможность выразить правила на одном из нескольких разных языков. Поэтому я определил интерфейс к действующему механизму правил, который предлагает методы, которые понадобятся приложению для запроса текущего набора правил. За этим интерфейсом будет один другой тип движка, в зависимости от исходного языка.
Теперь я хотел бы создать движок правил в соответствии с расширением файла правил. Но я получаю некоторые ошибки, которые мне трудно преодолеть.
Позвольте мне сначала предложить этот упрощенный скелет:
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
с другой стороны, чтобы обеспечить адекватный конструктор, но как можно больше я хотел бы избежать такого дублирования.
Спасибо за понимание!
1 ответ
(отредактировано: я принял свой собственный ответ из-за отсутствия других, но его самая важная часть - комментарий @seh ниже)
Следуя комментарию @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)
компилятор тоже счел негодным)