简体   繁体   English

为什么这种模式匹配在Scala中没有像预期的那样工作?

[英]Why doesn't this pattern matching work as expected in Scala?

I'm trying to replicate the powerful pattern matching example that Joshua Suereth presented in his Devoxx 2013 talk titled "How to wield Scala in the trenches". 我试图复制Joshua Suereth在2013年Devoxx的题为“如何在战壕中使用Scala”的演讲中提出的强大模式匹配示例。 Unfortunately I cannot achieve what he described and I cannot understand what is wrong. 不幸的是,我无法实现他所描述的,我无法理解什么是错的。 Can someone give me a hint at what I'm missing? 有人能给我一些暗示我缺少的东西吗? (My Scala version is 2.10.3) (我的Scala版本是2.10.3)

Please see the self contained code below: 请参阅下面的自包含代码:

case class Person(name: String, residence: Seq[Residence])
case class Residence(city: String, country: String)

object LivesIn {
  def unapply(p: Person): Option[Seq[String]] =
    Some(
      for(r <- p.residence)
      yield r.city
    )
}

class StringSeqContains(value: String) {
  def unapply(in: Seq[String]): Boolean =
    in contains value
}

object PatternPower extends App {

  val people =
    Seq(Person("Emre", Seq(Residence("Antwerp", "BE"))),
      Person("Ergin", Seq(Residence("Istanbul", "TR"))))

  val Istanbul = new StringSeqContains("Istanbul")

  // #1 does not work as expected, WHY?
  println(
    people collect {
      case person @ LivesIn(Istanbul) => person
    }
  )

  // #2 works as expected
  println(
    people collect {
      case person @ LivesIn(cities) if cities.contains("Istanbul") => person
    }
  )

  // #3 works as expected
  println(
    people collect {
      case person @ Person(_, res) if res.contains(Residence("Istanbul", "TR")) => person
    }
  )

}

When I compile and run it I get: 当我编译并运行它时,我得到:

List()
List(Person(Ergin,List(Residence(Istanbul,TR))))
List(Person(Ergin,List(Residence(Istanbul,TR))))

As denoted in the source code, I fail to grasp why the first pattern does not produce the same result as the remaining two pattern matches. 如源代码所示,我无法理解为什么第一个模式不会产生与其余两个模式匹配相同的结果。 Any ideas why? 有什么想法吗?

Your LivesIn extractor requires a Seq for an argument. 你的LivesIn提取器需要一个参数的Seq。

The following variation does what you expect: 以下变体符合您的期望:

println(
  people collect {
    case person @ LivesIn(List("Istanbul")) => person
  }
)

After some thinking and Googling, I realized that one should add () to the inner extractor (thanks to The Neophyte's Guide to Scala Part 1: Extractors ). 经过一些思考和谷歌搜索,我意识到应该添加()到内部提取器(感谢新手的Scala指南第1部分:提取器 )。

In other words, the following works as expected: 换句话说,以下工作符合预期:

people collect {
  case person @ LivesIn(Istanbul()) => person
}

whereas the following code silently, without any complaints, returns List() : 而以下代码默默地,没有任何投诉,返回List()

people collect {
  case person @ LivesIn(Istanbul) => person
}

Unless I'm mistaken in another way (eg there is way to make it work without parantheses), I think technical presenters should be more careful with the code snippets / pseudo-code snippets (so that some of the curious audience will not lose sleepless hours ;-) 除非我以另一种方式弄错(例如,有办法让它没有parantheses工作),我认为技术主持人应该更加小心代码片段/伪代码片段(以便一些好奇的观众不会失去失眠小时 ;-)

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

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