Scala中带case的flatMap可行,普通参数写法为何报错?
为什么Scala中这段不带case的flatMap代码无法运行?
咱们把问题拆解开来看,核心在于Map的flatMap方法对传入函数的参数类型要求,以及两种写法的本质差异:
1. 先明确Map的flatMap方法签名
对于Map[K, V]来说,它的flatMap方法要求传入的函数必须是这样的:
f: ((K, V)) => TraversableOnce[(K, V)]
划重点:这个函数的输入是单个的元组对象(K, V),而不是两个分开的K和V独立参数。
2. 带case的写法为什么能正常工作?
看这段能运行的代码:
m.flatMap { case(k,v) => h(k,v) }
这里的{ case(k,v) => ... }本质是一个偏函数(PartialFunction),Scala会自动帮我们把它适配成接受元组的函数。当flatMap把Map中的每个键值对(也就是(Int, Int)元组)传进来时,case(k,v)会自动解构这个元组,把里面的元素分别赋值给k和v,再传给h函数,完全符合flatMap的参数要求,所以能正常过滤掉v≤2的键值对,返回Map(2 -> 4, 3 -> 6)。
3. 不带case的写法为什么报错?
再看这段执行失败的代码:
m.flatMap { (k,v) => h(k,v) }
这里的(k,v) => ...定义的是一个接受两个独立参数的函数,类型是(Int, Int) => Option[(Int, Int)],但flatMap需要的是接受单个元组参数的函数((Int, Int)) => Option[(Int, Int)],两者类型完全不匹配!
编译器遇到这种类型不匹配,就会抛出对应的报错:
expected: Int, actual:(Int, Int):编译器误以为你要给函数传第一个参数k(类型为Int),但实际传入的是整个键值对元组(Int, Int),类型对不上;Missing Type parameter v:因为类型推断逻辑被打乱,编译器无法正确识别第二个参数v的类型,所以抛出这个错误。
如果想让不带case的写法工作,你可以手动解构元组,比如:
m.flatMap { tuple => h(tuple._1, tuple._2) }
不过显然,带case的写法是最直观简洁的。
内容的提问来源于stack exchange,提问作者Jwan622
相关产品推荐
相关产品推荐

