我正在阅读Demystifying Scala Type System,在第17张幻灯片中有一个片段:
class Test[+A] {
def test[B >: A](b: B): String = b.toString
}
幻灯片说方法测试将接受A类或任何超类型的A.但似乎我可以通过任何类型进行测试。
vat t = new Test[Int]
t.test("foo")
t.test(List(1, 2, 3))
当我阅读Scala编程时,我也有同样的困惑。
答案 0 :(得分:6)
这里要记住的重要一点是Any
是任何类型的超类型,即
Any >: A
特别假设
val t = new Test[Int]
这是A
是Int
。现在我们打电话
t.test("foo")
"foo"
的类型为String
,但字符串是Any
的子类型,因此可以这样考虑,因此可以使用{{1}调用test[B >: A](b : B)
} b
和"foo"
为B
。
以下示例应说明这一点,请考虑
Any
现在,使用
class Test[+A](a : A) {
def test[B >: A](b : B) : (A,B) = (a,b)
}
我们得到了
val t = new Test(3)
val x = t.test("foo")
最后,要添加一些细节,Scala不会总是选择x: (Int, Any) = (3,foo)
,而是Any
和A
的最不常见的超类型。对于B
和Any
(http://www.scala-lang.org/old/node/128),这恰好是Int
,但对于其他示例可能会有所不同,例如
String
我们会得到
val s = new Test(Nil)
val y = s.test("foo")
val z = s.test(List(1))
另请注意,下限不会阻止传递y: (scala.collection.immutable.Nil.type, java.io.Serializable) = (List(),foo)
z: (scala.collection.immutable.Nil.type, List[Int]) = (List(),List(1))
A
所以,问题是,什么是低级类型边界有用?一个可能的答案是它们可以用于“控制”“输出”位置的类型,如通常用于协变类型参数,例如,参见http://docs.scala-lang.org/tutorials/tour/lower-type-bounds.html粗略地说,当将元素附加到(协变)时类型scala> val a = new Test(new AnyRef())
a: Test[java.lang.Object] = Test@6771a12
scala> a.test("foo")
res6: (java.lang.Object, java.lang.Object) = (java.lang.Object@78b99f12,foo)
的列表,您要确保结果列表“至少”类型为A
。 (我很抱歉这部分内容很浪漫,但是因为它超出了原始问题的范围,我只是想简要介绍一下为什么需要它们,为了得到完整答案,最好创建它一个新问题)
答案 1 :(得分:0)
由于Any,该参数可以接受任何类型。但是,我不认为这个例子非常清楚。如果您将此代码段放入工作表
如果定义了返回类型是与B相关的东西,你会看到问题
class Test[+A] {
def test[B >: A](b: B): B = b
}
class A
class B extends A
val test = new Test[B]
val t = test.test("test")
返回类型为非字符串,对象。基本上,它失去了类型参考。
我们需要定义这样的原因是A是协变。在这种情况下,由于 Function1 [-A,+ B] 的定义,它只能用于返回类型而非参数。如果使用def测试(b:A).....它将有编译错误:
协变类型A出现在值b的类型A的逆变位置 def test(b:A):String = b.toString
此外,如果要约束超类型,可以有多个选项。其中一个是使用隐式来约束类型。
class C
class CCC extends C
def test[B >: A](b: B)(implicit ev: B =:= C): B = b
val test = new Test[CCC]
test.test(new C)//ok
test.test("123")//compilation error