Могу ли я использовать аннотации типа класса, чтобы принять решение о типе результата метода класса? - PullRequest
2 голосов
/ 28 апреля 2019

У меня есть несколько с двумя наследниками.

trait MyTrait[T <: MyTrait[T]] {
  this: T =>
}

class MyTraitImpl1 extends MyTrait[MyTraitImpl1]
class MyTraitImpl2 extends MyTrait[MyTraitImpl2]

Эти наследники являются взаимоисключающими и могут быть получены друг от друга, поэтому существует другой класс, набранный с помощью MyTrait.

class TypedClass[T <: MyTrait](value: T) {

  def anotherValue[O <: MyTrait]: O
}

Могу ли я сделать что-нибудь, чтобы метод anotherValue возвратил точно MyTraitImpl1, если TypedClass напечатано с MyTraitImpl2 и наоборот?

1 Ответ

4 голосов
/ 28 апреля 2019

Если вы можете изменить MyTrait, MyTraitImpl1, MyTraitImpl2, вы можете добавить тип члена OtherType

  trait MyTrait[T <: MyTrait[T]] {
    this: T =>
    type OtherType <: MyTrait[_]
  }

  class MyTraitImpl1 extends MyTrait[MyTraitImpl1] {
    override type OtherType = MyTraitImpl2
  }
  class MyTraitImpl2 extends MyTrait[MyTraitImpl2] {
    override type OtherType = MyTraitImpl1
  }


  class TypedClass[T <: MyTrait[T]](value: T) {

    def anotherValue: T#OtherType = ???
  }

//    OR
//  class TypedClass[T <: MyTrait[T]](val value: T) {
//
//    def anotherValue: value.OtherType = ???
//  }

  new TypedClass[MyTraitImpl1](new MyTraitImpl1).anotherValue : MyTraitImpl2
  new TypedClass[MyTraitImpl2](new MyTraitImpl2).anotherValue : MyTraitImpl1
//  new TypedClass[MyTraitImpl1](new MyTraitImpl1).anotherValue : MyTraitImpl1 // doesn't compile
//  new TypedClass[MyTraitImpl2](new MyTraitImpl2).anotherValue : MyTraitImpl2 // doesn't compile

Если вы не можете изменить MyTrait, MyTraitImpl1, MyTraitImpl2, вы можете создать класс типа OtherType

  trait MyTrait[T <: MyTrait[T]] {
    this: T =>
  }

  class MyTraitImpl1 extends MyTrait[MyTraitImpl1]
  class MyTraitImpl2 extends MyTrait[MyTraitImpl2]

  trait OtherType[T <: MyTrait[T]] {
    type Out <: MyTrait[_]
  }

  object OtherType {
    type Aux[T <: MyTrait[T], Out0 <: MyTrait[_]] = OtherType[T] { type Out = Out0 }
    def instance[T <: MyTrait[T], Out0 <: MyTrait[_]]: Aux[T, Out0] = new OtherType[T] { type Out = Out0 }

    implicit val otherType1: Aux[MyTraitImpl1, MyTraitImpl2] = instance
    implicit val otherType2: Aux[MyTraitImpl2, MyTraitImpl1] = instance
  }

  class TypedClass[T <: MyTrait[T]](value: T) {

    def anotherValue(implicit otherType: OtherType[T]): otherType.Out = ???
  }
...