似乎能够根据抽象函数/方法的类型有效地对实现方法的合法返回值进行断言。 我直觉地感觉(大多数)下面的编译器行为是有道理的,但我很感激清楚地解释为什么我应该能够断言
def f[T](t: T): T
只能是身份功能(E类编译除外)。我可以理解我们对T 一无所知,因为它没有限制,但是在那个解释中存在差距。 报告“找到scala.Int(42)required Int”的编译器并没有让我更接近光明。
trait A{ def f[T](t: T): T }
// compiles
class B extends A{ override def f[Int](t: Int): Int = t }
// does not compile
class C extends A{ override def f[Int](t: Int): Int = t + 1 }
// does not compile
class D extends A{ override def f[Int](t: Int): Int = 42 }
// compiles
class E extends A{ override def f[Int](t: Int): Int = 42.asInstanceOf[Int] }
// compiles
class F extends A{ override def f[Int](t: Int): Int = identity(t) }
答案 0 :(得分:4)
示例中的问题是示例中的Int
不正常的32位整数类型(scala.Int
);相反,您有一个恰好名为Int
的类型参数。这让您感到困惑:您认为Int
是scala.Int
,但事实并非如此,这是一个名称混乱的类型参数。
所以,例如:
class C extends A{ override def f[Int](t: Int): Int = t + 1 }
并不意味着您要定义一个采用scala.Int
的方法;您正在使用名称为Int
的类型参数定义方法。您可以给它任何其他名称,例如X
,然后它将完全相同:
class C extends A{ override def f[X](t: X): X = t + 1 }
它没有编译,因为类型参数没有约束,因此编译器不知道该类型具有+
方法。
答案 1 :(得分:1)
Jesper对主要问题有正确答案:[Int]
没有为Int
填写T
类型,它正在创建一个容易混淆名为{{1}的新泛型类型参数}}
但我也有一个附录:
你有点过于相信用户不会做鬼鬼祟祟的事情,即使它在运行时是有效的。
Int
不再是身份功能,是吗?如果您禁止匹配和def f[T](t: T): T = (t match {
case i: Int => -i
case s: String => s.reverse
case b: Boolean => !b
case o: Option[_] => None
case s: Seq[_] => throw new Exception("Ack")
case _ => t
}).asInstanceOf[T]
以及异常等,那么它必须是身份。
答案 2 :(得分:1)
由于没有人回答问题的其他部分:
通常,此属性称为 parametricity ,您从中获得的保证称为 free theorems 。顺便说一下,如果你忽略了typecase(以及没有标记的副作用),那么这只会占用,所以Scala的很大一部分都不算数。