scala – 继承和(自动?)类型转换
请看一下下面的代码,其中Extractor [A,B]是通用框架的一部分,其他一切应该被视为“客户端代码”(我把它煮了很多,并重命名为所有内容.所以不要请注意,提取器似乎不太有用).
scala> abstract class Extractor[A,B] { | def extract(d:A):B | def stringRepr(d:A):String | } defined class Extractor scala> sealed abstract class Value defined class Value scala> case class IntValue(i:Int) extends Value defined class IntValue scala> case class StringValue(s:String) extends Value defined class StringValue scala> case class Data(i:Int,s:String) defined class Data scala> sealed abstract class MyExtractor[Value] extends Extractor[Data,Value] { | def stringRepr(d:Data) = extract(d) match { | case IntValue(i) => i.toString | case StringValue(s) => s | } | } defined class MyExtractor scala> class IntExtractor(name:String) extends MyExtractor[IntValue] { | def extract(d:Data) = IntValue(d.i) | } defined class IntExtractor scala> class StringExtractor(name:String) extends MyExtractor[StringValue] { | def extract(d:Data) = StringValue(d.s) | } defined class StringExtractor 所以简而言之,Extractor [A,B]用于从A中提取一些值B,并做一些本节目代码中未表示的其他事情.在“客户端代码”中出于类型savety的原因使用抽象类Value和MyExtractor. scala> val l = List.empty[MyExtractor[Value]] l: List[MyExtractor[Value]] = List() scala> new IntExtractor("test1") :: l res5: List[MyExtractor[_ >: IntValue <: Value]] = List(IntExtractor@1fd96c5) 尝试将IntExractor转换为超类 scala> new IntExtractor("test"):MyExtractor[Value] <console>:24: error: type mismatch; found : IntExtractor required: MyExtractor[Value] new IntExtractor("test"):MyExtractor[Value] ^ scala> new IntExtractor("test"):Extractor[Data,Value] <console>:24: error: type mismatch; found : IntExtractor required: Extractor[Data,Value] new IntExtractor("test"):Extractor[Data,Value] 当我像这样定义IntExtractor时,我知道一切都很好 scala> class IntExtractor(name:String) extends MyExtractor[Value] { | def extract(d:Data) = IntValue(d.i) | } defined class IntExtractor scala> new IntExtractor("test"):Extractor[Data,Value] res17: Extractor[Data,Value] = IntExtractor@1653d7a 但我不明白,为什么它不能像我上面尝试的那样工作. 解决方法
就我所知,您正在寻找的概念是“协方差”.仅仅因为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的提取器的地方使用它. 何时可以宣布违反和协方差的限制.例如,逆变类型参数只能用作方法参数,协变参数只能用作方法返回值或val.两者都不能用作变量.嵌套类型参数会变得更复杂,但规则基本上归结为“合理的地方”,并且您的示例符合所有这些规则. 另外注意,您的示例中的所有抽象类都应该被声明为traits.只要您的抽象类不需要构造函数参数,将它们声明为特征就可以为您提供更多的重用机会. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |