简体   繁体   English

Scala在使用函数时出现“类型不匹配错误”,但对于方法来说效果很好

[英]Scala 'type mismatch error' while using a function but works fine for method

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

getting a type mismatch error while using stringToIntFunction in flatMap 在flatMap中使用stringToIntFunction时遇到类型不匹配错误

type mismatch;
  found   : String => Option[Int]
  required: String => scala.collection.GenTraversableOnce[?]
println("with functon is: " + stringAndIntArray.flatMap(stringToIntFunction))
                                                    ^

Why is it? 为什么?

flatMap requires lambda, you are passing it a normal method flatMap需要lambda,您将其传递给普通方法

Here is the fix 这是解决方法

stringAndIntArray.flatMap(stringToIntMethod _)

Scala REPL 斯卡拉REPL

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)

Normal method can be converted to lambda using underscore 普通方法可以使用下划线转换为lambda

More examples for clarity 为了清楚起见,有更多示例

scala> 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

Also adding a comment from lambda. 还添加了来自lambda的评论。 xy. XY。 x X

f _ is syntactic sugar for f(_) which is again syntactic sugar for x => f(x)

I'm still puzzled myself about why this example does not work. 我仍然对为什么这个例子不起作用感到困惑。 I assume it has to do with Scala's type inference. 我认为这与Scala的类型推断有关。 If you look at the error message 如果您查看错误消息

 found   : String => Option[Int]
 required: String => scala.collection.GenTraversableOnce[?]

it says that the return value of stringToIntFunction does not fit the argument value of flatMap . 它说stringToIntFunction的返回值不适合flatMap的参数值。 Indeed, the type test 确实,类型测试

Some(1).isInstanceOf[TraversableOnce[Int]]

leads to: 导致:

<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

Funnily enough, when I change the return type of your function to TraversableOnce[Int] , it works: 有趣的是,当我将函数的返回类型更改为TraversableOnce[Int] ,它会起作用:

def stringToIntFunction : String => TraversableOnce[Int] = (in:String) => {
   //...
}

leads to 导致

scala> stringAndIntArray.flatMap(stringToIntFunction)
res28: Array[Int] = Array(1, 2)

The reason is that even though Option does not derive from TraversableOnce , there is an implicit conversion: 原因是,即使Option不是从TraversableOnce派生的,也存在隐式转换:

 scala> def f(to : TraversableOnce[Int]) = to.size
 f: (to: TraversableOnce[Int])Int
 scala> f(Some(1))
 res25: Int = 1

This has also been noticed in a different question before. 之前在另一个问题中也注意到了这一点。

My theory is that for a method the return value is explicitly known to the compiler which allows it to detect the presence of an implicit conversion from Option[Int] => TraversableOnce[Int] . 我的理论是,对于一个方法,返回值对于编译器来说是明确已知的,这使它可以检测到Option[Int] => TraversableOnce[Int]隐式转换的存在。 But in the case of a function value the compiler would only look for an implicit conversion between (String => Option[Int]) => (String => TraversableOnce[Int]) . 但是对于函数值,编译器只会在(String => Option[Int]) => (String => TraversableOnce[Int])之间寻找隐式转换。 When the lambda application stringToIntFunction _ is passed instead, the compiler seems to see that it can apply the implicit conversion again. 相反,当传递lambda应用程序stringToIntFunction _ ,编译器似乎看到它可以再次应用隐式转换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM