返回值由Scala中的函数类型“约束”

时间:2012-11-26 14:26:26

标签: function scala compiler-construction types

似乎能够根据抽象函数/方法的类型有效地对实现方法的合法返回进行断言。 我直觉地感觉(大多数)下面的编译器行为是有道理的,但我很感激清楚地解释为什么我应该能够断言

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

3 个答案:

答案 0 :(得分:4)

示例中的问题是示例中的Int 正常的32位整数类型(scala.Int);相反,您有一个恰好名为Int的类型参数。这让您感到困惑:您认为Intscala.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的很大一部分都不算数。