Ste*_*eve 18 for-loop scala map filter pattern-matching
要创建一个可以在Scala中用于理解的新类,似乎所有你需要做的就是定义一个map函数:
scala> class C[T](items: T*) {
| def map[U](f: (T) => U) = this.items.map(f)
| }
defined class C
scala> for (x <- new C(1 -> 2, 3 -> 4)) yield x
res0: Seq[(Int, Int)] = ArrayBuffer((1,2), (3,4))
Run Code Online (Sandbox Code Playgroud)
但这仅适用于简单的for循环,其中左侧没有模式匹配<-.如果您尝试在那里进行模式匹配,则会收到filter未定义方法的投诉:
scala> for ((k, v) <- new C(1 -> 2, 3 -> 4)) yield k -> v
<console>:7: error: value filter is not a member of C[(Int, Int)]
for ((k, v) <- new C(1 -> 2, 3 -> 4)) yield k -> v
Run Code Online (Sandbox Code Playgroud)
为什么需要过滤器来实现模式匹配?我原以为Scala会把上面的循环翻译成等效的map调用:
scala> new C(1 -> 2, 3 -> 4).map{case (k, v) => k -> v}
res2: Seq[(Int, Int)] = ArrayBuffer((1,2), (3,4))
Run Code Online (Sandbox Code Playgroud)
但这似乎工作正常,因此for循环必须转换为其他东西.什么是翻译成需要的filter方法?
rxg*_*rxg 18
简短的回答:根据Scala规范,您不需要为您给出的示例定义"过滤器"方法,但是有一个开放的错误,这意味着它当前是必需的.
答案很长:Scala语言规范中描述了适用于理解的desugaring算法.让我们从第6.19节"对于理解和循环"(我正在查看规范的2.9版)开始:
在第一步中,每个生成器p < - e,其中p对于e的类型不是无可辩驳的(第8.1节),由p < - e.withFilter {case p => true; case _ => false}
你问题的重点在于理解中的模式是否对于给定的表达式是"无可辩驳的".(模式是'< - '之前的位;表达式是之后的位.)如果它是"无可辩驳的",则不会添加withFilter,否则将需要它.
很好,但"无可辩驳"是什么意思?跳到规范的第8.1.14节("Irrefutable Patterns").粗略地说,如果编译器在匹配表达式时可以证明模式不会失败,那么模式是无可辩驳的,并且不会添加withFilter调用.
现在你的例子按预期工作是第8.1.14节中的第一种无可辩驳的模式,一种变量模式.因此第一个示例很容易让编译器确定withFilter不需要.
你的第二个例子可能是第三种无可辩驳的模式,一种构造函数模式.试图匹配(k,v)Tuple2[Any,Any]与a Tuple2[Int,Int](参见规范中的8.1.6和8.1.7节))成功,因为Int无可辩驳Any.因此,第二种模式也是无可辩驳的,并且(不应该)需要一种withFilter方法.
在丹尼尔的例子中,Tuple2[Any,Any]不是无可辩驳的Any,因此添加了withFilter调用.
顺便说一句,错误消息谈论了一个filter方法,但规范谈到withFilter- 它是用Scala 2.8改变的,看到这个问题和答案的血淋淋的细节.
Dan*_*ral 12
看到不同:
scala> for ((k, v) <- List(1 -> 2, 3 -> 4, 5)) yield k -> v
res22: List[(Any, Any)] = List((1,2), (3,4))
scala> List(1 -> 2, 3 -> 4, 5).map{case (k, v) => k -> v}
scala.MatchError: 5
Run Code Online (Sandbox Code Playgroud)