Это дополнительный вопрос к предыдущему , вот мой текущий пример:
тест / 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), я получу точно такой же результат.
Я что-то упускаю здесь очевидное или есть другой способ добиться того, что я пытаюсь сделать здесь?