为什么必须在 Scala 的 for 循环中为模式匹配定义过滤器? [英] why does filter have to be defined for pattern matching in a for loop in scala?

查看:34
本文介绍了为什么必须在 Scala 的 for 循环中为模式匹配定义过滤器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

要创建一个可以在 Scala 中用于理解的新类,您似乎只需要定义一个 map 函数即可:

To create a new class that can be used in a Scala for comprehension, it seems that all you have to do is define a map function:

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

但这仅适用于 <- 左侧没有模式匹配的简单 for 循环.如果你尝试在那里进行模式匹配,你会得到一个关于 filter 方法没有定义的抱怨:

But that only works for simple for loops where there is no pattern matching on the left hand side of <-. If you try to pattern match there, you get a complaint that the filter method is not defined:

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

为什么这里需要过滤器来实现模式匹配?我原以为 Scala 会将上述循环转换为等效的 map 调用:

Why is filter required to implement the pattern matching here? I would have thought Scala would just translate the above loop into the equivalent map call:

scala> new C(1 -> 2, 3 -> 4).map{case (k, v) => k -> v}
res2: Seq[(Int, Int)] = ArrayBuffer((1,2), (3,4))

但这似乎工作正常,因此必须将 for 循环转换为其他内容.需要filter方法翻译成什么?

But that seems to work fine, so the for loop must be translated into something else. What is it translated into that needs the filter method?

推荐答案

简短的回答:根据 Scala 规范,您不需要为您提供的示例定义过滤器"方法,但是有一个 <一个 href="https://issues.scala-lang.org/browse/SI-1336" rel="nofollow noreferrer">open bug 表示当前需要它.

The short answer: according to the Scala specs, you shouldn't need to define a 'filter' method for the example you gave, but there is an open bug that means it is currently required.

长答案:应用于理解的脱糖算法在中描述Scala 语言规范.让我们从第 6.19 节For Comprehensions and For Loops"开始(我正在看规范的 2.9 版):

The long answer: the desugaring algorithm applied to for comprehensions is described in the Scala language specification. Let's start with section 6.19 "For Comprehensions and For Loops" (I'm looking at version 2.9 of the specification):

在第一步中,每个生成器 p <- e,其中 p 对于 e 的类型不是无可辩驳的(第 8.1 节)被替换为 p <- e.withFilter { case p => true;案例_ => 假}

In a first step, every generator p <- e, where p is not irrefutable (§8.1) for the type of e is replaced by p <- e.withFilter { case p => true; case _ => false }

您的问题的重点是,对于给定的表达式,理解中的模式是否无可辩驳".(模式是 '<-' 之前的位;表达式是之后的位.)如果它是无可辩驳的",则不会添加 withFilter,否则将需要.

The important point for your question is whether the pattern in the comprehension is "irrefutable" for the given expression or not. (The pattern is the bit before the '<-'; the expression is the bit afterwards.) If it is "irrefutable" then the withFilter will not be added, otherwise it will be needed.

好吧,但无可辩驳"是什么意思?跳到规范的第 8.1.14 节(无可辩驳的模式").粗略地说,如果编译器能证明在匹配表达式时模式不会失败,那么模式是无可辩驳的,并且不会添加 withFilter 调用.

Fine, but what does "irrefutable" mean? Skip ahead to section 8.1.14 of the spec ("Irrefutable Patterns"). Roughly speaking, if the compiler can prove that the pattern cannot fail when matching the expression then the pattern is irrefutable and the withFilter call will not be added.

现在您按预期工作的示例是第 8.1.14 节中的第一种不可反驳的模式,可变模式.所以第一个例子很容易让编译器确定 withFilter 不是必需的.

Now your example that works as expected is the first type of irrefutable pattern from section 8.1.14, a variable pattern. So the first example is easy for the compiler to determine that withFilter is not required.

你的第二个例子可能是第三种无可辩驳的模式,构造器模式.尝试将 Tuple2[Any,Any] 的 (k,v) 与 Tuple2[Int,Int] 匹配(参见第 8.1.6 节和第 8.1.7 节)规范)) 成功,因为 IntAny 来说是无可辩驳的.因此,第二种模式也是无可辩驳的,不需要(不应该)使用 withFilter 方法.

Your second example is potentially the third type of irrefutable pattern, a constructor pattern. Trying to match (k,v) which is Tuple2[Any,Any] against a Tuple2[Int,Int] (see section 8.1.6 and 8.1.7 from the specification)) succeeds since Int is irrefutable for Any. Therefore the second pattern is also irrefutable and doesn't (shouldn't) need a withFilter method.

在 Daniel 的例子中,Tuple2[Any,Any]Any 不是无可辩驳的,所以添加了 withFilter 调用.

In Daniel's example, Tuple2[Any,Any] isn't irrefutable against Any, so the withFilter calls gets added.

顺便说一句,错误消息谈到了 filter 方法,但规范谈到了 withFilter - 它在 Scala 2.8 中发生了变化,请参阅 这个问题和答案 了解血腥细节.

By the way, the error message talks about a filter method but the spec talks about withFilter - it was changed with Scala 2.8, see this question and answer for the gory details.

这篇关于为什么必须在 Scala 的 for 循环中为模式匹配定义过滤器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆