Храните коллекцию конструкторов для типов, которые все соответствуют одному и тому же интерфейсу

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

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

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

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

Другие вопросы по тегам