#scala #path-dependent-type #abstract-type
#scala #path-dependent-type #абстрактный тип
Вопрос:
Вот простой пример:
trait Sup {
type A
def a: A
def b: A
}
trait Sub1 extends Sup {
override type A = Product
override def a = "s" -> "s"
}
trait Sub2 extends Sup {
override type A = Serializable
override def b = "s" -> "s"
}
object SS extends Sub1 with Sub2
Очевидно, что это вызовет ошибку компиляции, поскольку оба override type A
являются взаимоисключающими. Это противоречит интуиции, поскольку Product и Serializable обычно используются вместе. В качестве альтернативы я могу определить:
trait Sup {
type A
def a: A
}
trait Sub1 extends Sup {
override type A <: Product
override def a = "s" -> "s"
}
trait Sub2 extends Sup {
override type A <: Serializable
override def b = "s" -> "s"
}
object SS extends Sub1 with Sub2 {
override type A = Product with Serializable
}
Это делает определение a и b недействительным, поскольку тип A не был конкретизирован, кроме того, строка override type A = Product with Serializable
явно является шаблонной и может быть выведена вместо этого.
Каков правильный способ определить абстрактный тип, который допускает смешивание алмазов, избегая при этом шаблонного явного определения его во всех реализациях?
Комментарии:
1.
override type A = Product with Serializable
не является шаблонным (его нельзя вывести). Можно было бы определитьobject SS extends Sub1 with Sub2 { case class MyClass(i: Int); override type A = MyClass; override def a = MyClass(1) }
.MyClass
отличается отProduct with Serializable
типа. Вы должны указать, какой тип вы имеете в виду в objectSS
.2. Вероятно, можно было бы сделать вывод, что это
object SS extends Sub1 with Sub2 { override type A <: Product with Serializable }
(безdef a
). Что ж, Scala решила быть здесь более явной.3. В вашем случае MyClass <: Product с Serializable , поэтому это сужение необязательно. Но вы правы, шаблонность не является важной проблемой, поэтому я меняю свой пример на что-то более серьезное (оправданное, но не может быть скомпилировано)
Ответ №1:
Я думаю, вы потеряли нижние границы.
"s" -> "s"
имеет тип (String, String)
, который является подтипом Product
(и Serializable
) , но не подтипом A <: Product
(или A <: Serializable
).
Попробуйте
trait Sup {
type A
def a: A
def b: A
}
trait Sub1 extends Sup {
override type A >: (String, String) <: Product
override def a = "s" -> "s"
}
trait Sub2 extends Sup {
override type A >: (String, String) <: Serializable
override def b = "s" -> "s"
}
object SS extends Sub1 with Sub2 {
override type A = Product with Serializable
}
SS.a: (String, String)
SS.b: (String, String)
implicitly[SS.A =:= (Product with Serializable)]
Если вы укажете возвращаемый тип Sub1#a
, Sub2#b
чтобы быть A
(выше они были выведены как (String, String)
, т. е. возвращаемый тип был сужен при переопределении метода), то
trait Sup {
type A
def a: A
def b: A
}
trait Sub1 extends Sup {
override type A >: (String, String) <: Product
override def a: A = "s" -> "s"
}
trait Sub2 extends Sup {
override type A >: (String, String) <: Serializable
override def b: A = "s" -> "s"
}
object SS extends Sub1 with Sub2 {
override type A = Product with Serializable
}
SS.a: Product with Serializable
SS.b: Product with Serializable
implicitly[SS.A =:= (Product with Serializable)]
Вы можете сделать даже
object SS extends Sub1 with Sub2 {
override type A >: (String, String) <: Product with Serializable
}