使用scala.math.max减少Float数组
我对以下行为感到困惑 – 为什么使用math.max减少一个Int数组,但是一个Float数组需要一个包装函数?我记得这不是2.9的问题,但我不能完全确定.
$scala -version Scala code runner version 2.10.2 -- Copyright 2002-2013,LAMP/EPFL $scala scala> import scala.math._ scala> Array(1,2,4).reduce(max) res47: Int = 4 scala> Array(1f,3f,4f).reduce(max) <console>:12: error: type mismatch; found : (Int,Int) => Int required: (AnyVal,AnyVal) => AnyVal Array(1f,4f).reduce(max) ^ scala> def fmax(a: Float,b: Float) = max(a,b) fmax: (a: Float,b: Float)Float scala> Array(1f,4f).reduce(fmax) res45: Float = 4.0 更新:这确实有效 scala> Array(1f,2f,3f).reduce{(x,y) => math.max(x,y)} res2: Float = 3.0 所以它只是减少(math.max),这是不可缺少的? 解决方法
首先要注意的是math.max是重载的,如果编译器没有关于预期参数类型的提示,它只选择其中一个重载(我还不清楚哪些规则控制选择哪个重载,但是它会在这篇文章结束前变得清晰).
显然它有利于Int参数超过其他参数的重载.这可以在repl中看到: scala> math.max _ res6: (Int,Int) => Int = <function2> 该方法最具体,因为以下第一个编译(通过数字扩展转换),第二个不编译: scala> (math.max: (Float,Float)=>Float)(1,2) res0: Float = 2.0 scala> (math.max: (Int,Int)=>Int)(1f,2f) <console>:8: error: type mismatch; found : Float(1.0) required: Int (math.max: (Int,2f) ^ 测试是一个函数是否适用于另一个函数的参数类型,该测试包括任何转换. 现在,问题是:为什么编译器不能推断出正确的预期类型?它当然知道数组的类型(1f,4f)是数组[Float] 如果我们用reduceLeft替换reduce,我们可以得到一个线索:然后它编译得很好. 所以这肯定与reduceLeft和reduce的签名有所不同. case class MyCollection[A]() { def reduce[B >: A](op: (B,B) => B): B = ??? def reduceLeft[B >: A](op: (B,A) => B): B = ??? } MyCollection[Float]().reduce(max) // Fails to compile MyCollection[Float]().reduceLeft(max) // Compiles fine 签名略有不同. 在reduceLeft中,第二个参数被强制为A(集合的类型),因此类型推断是微不足道的:如果A == Float(编译器知道),那么编译器知道max的唯一有效重载是一个带有Float的重载作为其第二个论点.编译器只找到一个(max(Float,Float)),并且碰巧另一个约束(即B>:A)非常满足(因为B == A == Float for this overload). 这与reduce不同:第一个和第二个参数都可以是A的任何(相同)超类型(在我们的特定情况下,就是Float).这是一个更宽松的约束,虽然可以说在这种情况下编译器可以看到只有一种可能性,编译器在这里不够智能. 由于有一些有用的应用程序,例如: scala> Array(1f,3f).reduce[Any](_.toString+","+_.toString) res3: Any = 1.0,2.0,3.0 尝试对类型参数的每个可能替换进行重载解析是昂贵的,并且可能会根据您预期的类型更改结果;或者它是否必须发出歧义错误? 使用-Xlog-implicits -Yinfer-debug显示reduce(math.max)与首先解决param类型的版本之间的差异,其中首先发生重载解析: scala> Array(1f,3f).reduce(math.max(_,_)) [solve types] solving for A1 in ?A1 inferExprInstance { tree scala.this.Predef.floatArrayOps(scala.Array.apply(1.0,3.0)).reduce[A1] tree.tpe (op: (A1,A1) => A1)A1 tparams type A1 pt ? targs Float tvars =?Float } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |