为什么Scala不能从隐式证据中推断出类型
我试过这个并且它失败并出现错误:扩展函数缺少参数类型((x $29)=> x $29.sum).
有人可以解释为什么会这样吗?这只是Scala的类型推断不够强大吗? object HelloStackOverflow { implicit class Repro[T](val iterable: Iterable[T]) extends AnyVal { def foo[A,B,Z](bar: Iterable[B] => Z)(implicit evidence: T <:< (A,B)) = bar(iterable.map(_._2)) } List(("a",1),("b",2)).foo(_.sum) } (使用Scala 2.10) 解决方法
这是因为“必须完全知道匿名函数的参数类型”(Scala语言规范8.5).
当一个方法采用匿名函数时,scala使用它知道参数类型的事实,让调用者省略匿名函数参数的类型(让你写一些像x => x 1而不是x:Int = > x 1,或_.sum而不是x:Iterable [Int] => x.sum.这是scala中推理的一个很好的应用程序.但显然,这需要知道匿名的确切预期类型函数首先在这里不是这样的:匿名函数栏的参数是Iterable [B]类型.B是一个自由类型变量,不能以任何方式从早期的参数列表推断出来(之前没有方法foo中的参数列表. 这很合乎逻辑.在scala中,匿名函数就像一个对象(就像任何函数一样).创建一个匿名函数意味着实例化泛型类(扩展Function *),其中函数参数的类型被编码为Function *类的类型参数(再次读取它,我保证这句话有意义).在没有完全指定类型参数的情况下,根本不可能实例化任何泛型类.功能也不例外. 正如Impredicative在注释中所示,显式指定匿名函数参数的类型可修复编译错误: List(("a",2)).foo((a : Iterable[Int]) => a.sum) 甚至: List(("a",2)).foo((_.sum):Iterable[Int] => Int) 但在您的情况下,修复问题似乎很简单,而无需显式指定匿名函数的类型: object HelloStackOverflow { implicit class Repro[A,B](val iterable: Iterable[(A,B)]) extends AnyVal { def foo[Z](bar: Iterable[B] => Z) = bar(iterable.map(_._2)) } List(("a",2)).foo(_.sum) // works like a charm } 也许你之所以使用单一类型参数T(而不是上面我的例子中的参数A和B),并且证据表明T<:(A,B)就是你的真实代码中你在类Repro中有其他方法的原因这不需要T成对.在这种情况下,只需使用T类型参数创建另一个隐式类Repro2,然后在那里迁移其他方法.您不需要将所有的丰富内容放在同一个隐式类中. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |