Насколько я могу судить, концепция, которую вы ищете, это "ковариация". То, что IntValue
является подтипом Value
, не означает, что MyExtractor[IntValue]
является подтипом MyExtractor[Value]
. По умолчанию между этими двумя типами вообще нет связи подтипов. Чтобы создать такое отношение, вам нужно объявить MyExtractor
ковариантным по отношению к его параметру. Scala позволяет объявлять параметры типа ковариантными, добавляя «+» перед объявлением параметров типа. Это называется обозначением дисперсии.
sealed abstract class MyExtractor[+Value] extends Extractor[Data, Value] {
}
Scala также поддерживает контрастность параметров типа. Контравариантность аналогична ковариантности, но обратная, и выражается с помощью «-» дисперсии параметра типа. Ваш тип Extractor
является отличным примером места, где имеет смысл контравариантная запись.
abstract class Extractor[-A,+B] {
def extract(d:A):B
def stringRepr(d:A):String
}
Это означает, что если Foo
является подтипом Bar
, то Extractor[Bar, Baz]
является подтипом Extractor[Foo, Baz]
, что, если подумать, имеет смысл. Если что-то может извлечь нужные данные при передаче экземпляра супертипа, то по определению оно может извлечь его при передаче экземпляра подтипа. И наоборот, если Foo
является подтипом Bar
, то Extractor[Baz, Foo]
является подтипом Extractor[Baz, Bar]
. Это также имеет смысл. Если у вас есть экстрактор, который возвращает Foo
, вы, безусловно, можете использовать его там, где вам нужен экстрактор, который возвращает Bar
.
Существуют ограничения на возможность объявления контравариантности и ковариации. Например, параметры контравариантного типа могут использоваться только в качестве аргументов метода, а ковариантные параметры могут использоваться только в качестве возврата метода или значений. Ни один из них не может быть использован в качестве переменных. С параметрами вложенного типа все усложняется, но правила сводятся к тому, «где это разумно», и ваш пример соответствует всем им.
Дополнительное примечание: все ваши абстрактные классы в вашем примере, скорее всего, должны быть объявлены как черты. Пока ваши абстрактные классы не требуют аргументов конструктора, их объявление в качестве признаков дает вам еще несколько возможностей для повторного использования.