Общее управление потребителями экземпляров признаков с последствиями - PullRequest
0 голосов
/ 08 января 2019

Это дополнительный вопрос к предыдущему , вот мой текущий пример:

тест / package.scala

package object test {
    sealed trait BaseTrait {
        type T <: BaseState
        def state: T
    }
    case class Foo(state: FooState) extends BaseTrait
    case class Bar(state: BarState) extends BaseTrait

    sealed trait BaseState
    case class FooState(f: Integer = 1) extends BaseState
    case class BarState(s: String = "abc") extends BaseState
}

тест / база / BaseModel.scala

trait BaseModel[T <: BaseState] {
    var baseVar: Option[T] = None
}

тест / основание / BaseProcessor.scala

trait BaseProcessor[T <: BaseTrait#T] {
    def model: BaseModel[T]
    def process(x: T): Unit = model.baseVar = Option(x)
}

тест / Foo / FooProcessor.scala

class FooProcessor(val model: FooModel) extends BaseProcessor[Foo#T] {
    val v: Option[FooState] = model.baseVar
}

тест / Foo / FooModel.scala

class FooModel extends BaseModel[FooState]

тест / бар / BarProcessor.scala

class BarProcessor(val model: BarModel) extends BaseProcessor[Bar#T] {
    val v: Option[BarState] = model.baseVar
}

тест / бар / BarModel.scala

class BarModel extends BaseModel[BarState]

тест / Test.scala

object Test extends App {
    val test = Test2
    val foo = Foo(FooState())
    val bar = Bar(BarState())

    test.func(foo)
    test.func(bar)
}

тест / Test2.scala

class Test2 {
    private implicit val fooProcessor = new FooProcessor(new FooModel)
    private implicit val barProcessor = new BarProcessor(new BarModel)

    def func[T <: BaseTrait](p: T) {
        tfunc(p.state)
    }

    private def tfunc[T <: BaseTrait#T](p: T)(implicit processor: BaseProcessor[T]) {
        processor.process(p)
    }
}

Я пытаюсь добиться следующего:

  • не выставляйте различные процессоры, присутствующие внутри Test2, во внешний мир, поэтому «обычный» функционал и «типизированный» tfunc, которые должны обрабатывать все неявные действия
  • иметь возможность использовать / получать доступ к правильно типизированным состояниям внутри специализаций каждого BaseEditor (т. Е. Model.baseVar всегда должен быть правильного типа)
  • обрабатывать процессоры универсальным образом, так что tfunc настолько прост, насколько это возможно, и нет необходимости в типах / совпадениях шаблонов

Если я попытаюсь запустить то, что у меня есть, я получу следующую ошибку компилятора:

не удалось найти неявное значение для процессора параметров: base.BaseProcessor [p.T]

, который я не совсем понимаю, так как оба tfunc ожидают T <: BaseTrait#T, и неявные процессоры также имеют одинаковый параметр типа, поэтому я ожидаю, что компилятор будет соответствовать им.

Обратите внимание, что если я изменю абстрактный тип в BaseTrait на type T = BaseTrait, то теперь все последствия, похоже, соответствуют ожидаемому типу tfunc, поэтому я получаю и

неоднозначные неявные значения

ошибка компилятора. Мне кажется, по какой-то причине компилятор действительно не получает эти верхние границы правильно, но я, вероятно, ошибаюсь в своем предположении. Также, если я изменю tfunc на привязку к контексту и попытаюсь вызвать соответствующий процессор через implicitly[BaseProcessor[T]] (или implicitly[BaseProcessor[p.T]], где p - верхняя граница BaseTrait), я получу точно такой же результат.

Я что-то упускаю здесь очевидное или есть другой способ добиться того, что я пытаюсь сделать здесь?

...