我一直在使用Scala代码,遇到了我不理解的编译器错误。代码生成一对Ints的向量,然后尝试过滤它。
val L = for (x <- (1 to 5)) yield (x, x * x)
val f = (x: Int, y: Int) => x > 3
println(L.filter(f))
编译器抱怨尝试使用f
作为filter
方法的参数,编译器错误消息为:
error: type mismatch;
found : (Int, Int) => Boolean
required: ((Int, Int)) => Boolean
如何正确定义函数f
以满足所需的函数类型?我尝试在(x: Int, y: Int)
附近添加额外的括号,但这给了:
error: not a legal formal parameter
val f = ((x: Int, y: Int)) => x > 3
^
答案 0 :(得分:13)
f
的类型为Function2[Int, Int, Boolean]
。 L
的类型为IndexedSeq[Tuple2[Int, Int]]
,因此filter
需要Function1[Tuple2[Int, Int], Boolean]
类型的函数。每个FunctionN[A, B, .., R]
特征都有一个方法tupled
,它返回类型为Function1[TupleN[A, B, ..], R]
的函数。您可以在此处使用它将f
转换为L.filter
预期的类型。
println(L.filter(f.tupled))
> Vector((4,16), (5,25))
或者,您可以按照以下方式将f
重新定义为Function1[Tuple2[Int, Int], Boolean]
并直接使用。
val f = (t: (Int, Int)) => t._1 > 3
println(L.filter(f))
> Vector((4,16), (5,25))
答案 1 :(得分:6)
val f = (xy: (Int, Int)) => xy._1 > 3
println (L.filter (f))
如果你这样做
val f = (x: Int, y: Int) => x > 3
你定义了一个带有两个整数的函数,这个函数与一对整数作为参数的函数不同。
比较
scala> val f = (x: Int, y: Int) => x > 3
f: (Int, Int) => Boolean = <function2>
scala> val f = (xy: (Int, Int)) => xy._1 > 3
f: ((Int, Int)) => Boolean = <function1>
答案 2 :(得分:0)
如果您不想重写函数以明确使用Tuple2(由missingfaktor和用户未知建议),您可以定义一个隐式方法来自动执行。这使得函数f不受影响(你不必总是用Tuple2参数调用它)并且更容易理解,因为你仍然使用标识符x和y。
implicit def fun2ToTuple[A,B,Res](f:(A,B)=>Res):((A,B))=>Res =
(t:(A,B)) => f(t._1, t._2)
val L = for (x <- (1 to 5)) yield (x, x * x)
val f = (x: Int, y: Int) => x > 3
val g = (x: Int, y: Int) => x % 2 > y % 3
L.filter(f) //> Vector((4,16), (5,25))
L.filter(g) //> Vector((3,9))
f(0,1) //> false
f((4,2)) //> true
现在每个Function2也可以用作带有Tuple2作为参数的Function1,因为它在需要时使用隐式方法转换函数。
对于具有两个以上参数的函数,隐式defs看起来类似:
implicit def fun3ToTuple[A,B,C,Res](f:(A,B,C)=>Res):((A,B,C))=>Res =
(t:(A,B,C)) => f(t._1, t._2, t._3)
implicit def fun4ToTuple[A,B,C,D,Res](f:(A,B,C,D)=>Res):((A,B,C,D))=>Res =
(t:(A,B,C,D)) => f(t._1, t._2, t._3, t._4)
...