1

仅仅基于抽象函数/方法的类型,似乎可以有效地断言实现方法的合法返回值。我直觉地觉得(大部分)下面的编译器行为是有道理的,但我希望能清楚地解释为什么我应该能够断言

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) }
4

3 回答 3

4

您的示例中的问题是您Int的示例中的不是正常的 32 位整数类型(即scala.Int);相反,您有一个类型参数,它恰好被命名为Int. 这让您感到困惑:您认为您的Intis 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 }

它不编译是因为类型参数没有约束,所以编译器不知道该类型有+方法。

于 2012-11-26T14:41:40.410 回答
1

Jesper 对主要问题有正确的答案:[Int]没有填写Intfor的类型T,而是创建了一个新的泛型类型参数,名称令人困惑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]

不再完全是身份功能,是吗?如果您禁止匹配和asInstanceOf异常等,那么它必须是身份。

于 2012-11-26T14:58:37.843 回答
1

由于还没有人回答问题的另一部分:

通常,此属性称为参数性,您从中获得的保证称为自由定理。顺便说一句,这仅在您忽略类型大小写(和未标记的副作用)时才成立,因此 Scala 的很大一部分不计算在内。

于 2012-11-26T16:56:49.080 回答