def stringToIntMethod(input:String):Option[Int] = {
try{
Some(Integer.parseInt(input.trim()))
}
catch{
case e:Exception => None
}
}
val stringToIntFunction: (String) => Option[Int] = (in:String) => {
try{
Some(Integer.parseInt(in.trim()))
}
catch{
case e:Exception => None
}
}
val stringAndIntArray = Array("Hello", "1","2","Hi") //Input
println("with Method is: " + stringAndIntArray.flatMap(stringToIntMethod))
println("with functon is: " + stringAndIntArray.flatMap(stringToIntFunction))
在flatMap中使用stringToIntFunction时出现类型不匹配错误
type mismatch;
found : String => Option[Int]
required: String => scala.collection.GenTraversableOnce[?]
println("with functon is: " + stringAndIntArray.flatMap(stringToIntFunction))
^
为什么?
答案 0 :(得分:2)
flatMap
需要lambda,你传递的是普通方法
这是修复
stringAndIntArray.flatMap(stringToIntMethod _)
scala> def toInt(s: String): Option[Int] = Some(s.toInt)
toInt: (s: String)Option[Int]
scala> Array("1", "2", "3").flatMap(toInt _)
res1: Array[Int] = Array(1, 2, 3)
普通方法可以使用下划线
转换为lambdascala> def foo(s: String, i: Int): Double = 1
foo: (s: String, i: Int)Double
scala> foo _
res2: (String, Int) => Double = $$Lambda$1162/1477996447@62faf77
scala> foo(_, _)
res3: (String, Int) => Double = $$Lambda$1168/1373527802@30228de7
scala> foo(_: String, _: Int)
res5: (String, Int) => Double = $$Lambda$1183/477662472@2adc1e84
scala> foo("cow", _: Int)
res7: Int => Double = $$Lambda$1186/612641678@146add7b
scala> foo("Cow is holy", _: Int)
res8: Int => Double = $$Lambda$1187/1339440195@7d483ebe
还要添加lambda的评论。 XY。 X
f _ is syntactic sugar for f(_) which is again syntactic sugar for x => f(x)
答案 1 :(得分:2)
我仍然对自己为什么这个例子不起作用感到困惑。我认为它与Scala的类型推断有关。如果您查看错误消息
found : String => Option[Int]
required: String => scala.collection.GenTraversableOnce[?]
它表示stringToIntFunction的返回值不符合flatMap
的参数值。的确,型式试验
Some(1).isInstanceOf[TraversableOnce[Int]]
导致:
<console>:138: warning: fruitless type test: a value of type Some[Int] cannot also be a scala.collection.TraversableOnce[Int] (the underlying of TraversableOnce[Int])
Some(1).isInstanceOf[TraversableOnce[Int]]
^
res24: Boolean = false
有趣的是,当我将函数的返回类型更改为TraversableOnce[Int]
时,它可以正常工作:
def stringToIntFunction : String => TraversableOnce[Int] = (in:String) => {
//...
}
导致
scala> stringAndIntArray.flatMap(stringToIntFunction)
res28: Array[Int] = Array(1, 2)
原因是即使Option
不是来自TraversableOnce
,也会有隐式转换:
scala> def f(to : TraversableOnce[Int]) = to.size
f: (to: TraversableOnce[Int])Int
scala> f(Some(1))
res25: Int = 1
以前在另一个question中也注意到了这一点。
我的理论是,对于一个方法,编译器明确知道返回值,它允许它检测是否存在来自Option[Int] => TraversableOnce[Int]
的隐式转换。但是在函数值的情况下,编译器只会在(String => Option[Int]) => (String => TraversableOnce[Int])
之间寻找隐式转换。当传递lambda应用程序stringToIntFunction _
时,编译器似乎看到它可以再次应用隐式转换。