Art*_*sov 2 generics inheritance scala
我有一个我今天发现的问题清单.我是scala新手,因此我的问题可能微不足道.
我们假设我们有一个像这样的类:
abstract class A[+T] { def foo[S >: T](x: S): String }
Run Code Online (Sandbox Code Playgroud)
我们应该提供有用的子类和一些功能.
1)我的第一次尝试看起来像这样:
class B extends A[String] { def foo(x: String) = x }
Run Code Online (Sandbox Code Playgroud)
但scalac编译器不同意消息:
xxx@yyy:~$ scalac covariant.scala
covariant.scala:3: error: class B needs to be abstract, since method foo in class A of type [S >: String](x: S)String is not defined
class B extends A[String] { def foo(x: String) = x }
^
Run Code Online (Sandbox Code Playgroud)
首先,为什么scalac没有推断foo的泛型类型参数,它真的是一个复杂的任务吗?
2)接下来的尝试看起来更好,应该被接受,我认为:
class B extends A[String] { def foo[String](x: String) = x }
Run Code Online (Sandbox Code Playgroud)
但现在编译器让我大开眼界:
covariant.scala:3: error: type mismatch;
found : String(in method foo)
required: java.lang.String
class B extends A[String] { def foo[String](x: String) = x }
^
Run Code Online (Sandbox Code Playgroud)
看起来像是String和java.lang.String不匹配的问题.这是第二个问题:它真的是一个错误吗?
3)最后我决定将String类型切换为Date作为参数:
import java.util.Date
class B extends A[Date] { def foo[Date](x: Date) = x.toString }
Run Code Online (Sandbox Code Playgroud)
它编译时没有任何警告.最后一个问题是:为什么?我的第二个和第三个片段有什么区别?
顺便说一句,scalac版本是 2.9.1.final
真的,你所有的问题都源于同样的误解.
你有定义为"与一类参数,并且可以在任何类型的作用一个方法foo一类的后裔在T从其中T下降.
你提供了一个带有foo的类,它可以作用于T但不一定作用于后代(实际上,因为参数是协变的,foo实际上可以用于后代但是规范不够紧,不能捕获它) T的超类.
在另外两个问题中,您不小心重用了现有类型的名称.当你编写foo [Date]或foo [String]时,你并没有像你显然那样提到java.lang.String或java.lang.Date,而是指同名的新类型!这就是为什么你看到String和java.lang.String不匹配的原因 - 它们是两种不同的类型.
试试这个:
abstract class A[+T] { def foo[S >: T](x: S): String }
class B extends A[String] { def foo[S >: String](x: S) = x.toString }
Run Code Online (Sandbox Code Playgroud)
是的,S >: String因为String是最终的,所以有点无意义,但规范无法划分出每一个可能的边缘情况.
注意 我也是一个tyro,所以如果我的回答错误/误导,不要感到震惊.请记住:这个建议保证价值是您支付的两倍,或者您的钱被高兴地退还.
TOLD YA大错误:我颠倒了超类和子类.与三振出局一致的更正.
示例 OP不清楚为什么所有这些都是必要的.考虑以下功能
def foo3(a : A[String]) = a.foo(3)
Run Code Online (Sandbox Code Playgroud)
这是合法的,因为3(作为java.lang.Integer)是一个Object的例子,它是A的祖先.如果B.foo被定义为接受一个字符串而没有别的,则B的一个实例无法传递给foo3 .
| 归档时间: |
|
| 查看次数: |
319 次 |
| 最近记录: |