除列表之外的序列上的 Scala 模式匹配

发布于 2024-11-25 23:34:27 字数 807 浏览 0 评论 0 原文

我有以下代码,它对现在列表中的每个元素进行递归操作

def doMatch(list: List[Int]): Unit = list match {
  case last :: Nil  => println("Final element.")
  case head :: tail => println("Recursing..."); doMatch(tail)
}

,忽略可以通过 filter()foreach() 使用此功能,这工作得很好。但是,如果我尝试更改它以接受任何 Seq[Int],我会遇到问题:

  • Seq 没有​​ ::,但它确实有 +:,据我所知,这基本上是同样的事情。但是,如果我尝试在 head +: tail 上匹配,编译器会抱怨“错误:未找到:值+:”
  • Nil 特定于 List,并且我不确定用什么替换它。如果我解决了上一个问题,我将尝试 Seq()

这是我认为代码应该看起来的样子,除了它不起作用:

def doMatch(seq: Seq[Int]): Unit = seq match {
  case last +: Seq() => println("Final element.")
  case head +: tail  => println("Recursing..."); doMatch(tail)
}

编辑:这么多好的答案!我接受agilesteel的答案,因为他是第一个指出 :: 在我的示例中不是运算符,而是案例类,因此存在差异的答案。

I have the following code which recursively operates on each element within a List

def doMatch(list: List[Int]): Unit = list match {
  case last :: Nil  => println("Final element.")
  case head :: tail => println("Recursing..."); doMatch(tail)
}

Now, ignoring that this functionality is available through filter() and foreach(), this works just fine. However, if I try to change it to accept any Seq[Int], I run into problems:

  • Seq doesn't have ::, but it does have +:, which as I understand is basically the same thing. If I try to match on head +: tail however, the compiler complains 'error: not found: value +:'
  • Nil is specific to List, and I'm not sure what to replace it with. I'm going to try Seq() if I ever get past the previous problem

Here is how I think the code should look, except it doesn't work:

def doMatch(seq: Seq[Int]): Unit = seq match {
  case last +: Seq() => println("Final element.")
  case head +: tail  => println("Recursing..."); doMatch(tail)
}

Edit: So many good answers! I'm accepting agilesteel's answer as his was the first that noted that :: isn't an operator in my example, but a case class and hence the difference.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

荆棘i 2024-12-02 23:34:27

截至 2012 年 3 月的 IDE,这在 2.10+ 中有效:

  def doMatch(seq: Seq[Int]): Unit = seq match {
    case last +: Seq() => println("Final element.")
    case head +: tail  => println("Recursing..."); doMatch(tail)
  }                                               //> doMatch: (seq: Seq[Int])Unit

  doMatch(List(1, 2))                             //> Recursing...
                                                  //| Final element.

更一般地,为 Seq 添加了两个不同的 head/tail 和 init/last 分解对象,镜像附加/前置href="https://github.com/scala/scala/commit/b3efb3d493605d1c7e106e5f0a697b52ebb3d97c">SeqExtractors

List(1, 2) match { case init :+ last => last } //> res0: Int = 2                                              
List(1, 2) match { case head +: tail => tail } //> res1: List[Int] = List(2)                                               
Vector(1, 2) match { case init :+ last => last } //> res2: Int = 2                                              
Vector(1, 2) match { case head +: tail => tail } //> res3: scala.collection.immutable.Vector[Int] = Vector(2)

As of the ides of March 2012, this works in 2.10+:

  def doMatch(seq: Seq[Int]): Unit = seq match {
    case last +: Seq() => println("Final element.")
    case head +: tail  => println("Recursing..."); doMatch(tail)
  }                                               //> doMatch: (seq: Seq[Int])Unit

  doMatch(List(1, 2))                             //> Recursing...
                                                  //| Final element.

More generally, two different head/tail and init/last decomposition objects mirroring append/prepend were added for Seq in SeqExtractors:

List(1, 2) match { case init :+ last => last } //> res0: Int = 2                                              
List(1, 2) match { case head +: tail => tail } //> res1: List[Int] = List(2)                                               
Vector(1, 2) match { case init :+ last => last } //> res2: Int = 2                                              
Vector(1, 2) match { case head +: tail => tail } //> res3: scala.collection.immutable.Vector[Int] = Vector(2)
已下线请稍等 2024-12-02 23:34:27

有点作弊,但事情是这样的:

def doMatch(seq: Seq[Int]): Unit = seq match {
  case Seq(x) => println("Final element " + x)
  case Seq(x, xs@_*) => println("Recursing..." + x); doMatch(xs)
}

不要问我为什么 xs* 不起作用......

Kind of cheating, but here it goes:

def doMatch(seq: Seq[Int]): Unit = seq match {
  case Seq(x) => println("Final element " + x)
  case Seq(x, xs@_*) => println("Recursing..." + x); doMatch(xs)
}

Don't ask me why xs* doesn't work...

我还不会笑 2024-12-02 23:34:27

Scala 中有两个 :: (发音为 cons)。一种是在class List中定义的运算符,另一种是classList的子类),表示一个具有头和尾特征的非空列表。

head :: tail 是一个构造函数模式,它在语法上是从 ::(head, tail) 修改而来的。

:: 是一个案例类,这意味着为其定义了一个提取器对象。

There are two :: (pronounced cons) in Scala. One is an operator defined in class List and one is a class (subclass of List), which represents a non empty list characterized by a head and a tail.

head :: tail is a constructor pattern, which is syntactically modified from ::(head, tail).

:: is a case class, which means there is an extractor object defined for it.

思念绕指尖 2024-12-02 23:34:27

您实际上可以为 +: 定义一个对象来完全执行您正在寻找的操作:

object +: { 
  def unapply[T](s: Seq[T]) = 
    if(s.nonEmpty)
      Some(s.head, s.tail) 
    else
      None
}

scala> val h +: t = Seq(1,2,3)
h: Int = 1
t: Seq[Int] = List(2, 3)

然后您的代码将完全按照预期工作。

这是有效的,因为当用于模式匹配时,h +: t 相当于 +:(h,t)

You can actually define an object for +: to do exactly what you are looking for:

object +: { 
  def unapply[T](s: Seq[T]) = 
    if(s.nonEmpty)
      Some(s.head, s.tail) 
    else
      None
}

scala> val h +: t = Seq(1,2,3)
h: Int = 1
t: Seq[Int] = List(2, 3)

Then your code works exactly as expected.

This works because h +: t is equivalent to +:(h,t) when used for patten matching.

懷念過去 2024-12-02 23:34:27

我认为标准库中不存在对任意序列的模式匹配支持。不过,您可以在没有模式匹配的情况下完成此操作:

  def doMatch(seq: Seq[Int]) {
    if (seq.size == 1) println("final element " + seq(0)) else {
      println("recursing")
      doMatch(seq.tail)
    }
  }
  doMatch(1 to 10)

不过,您可以定义自己的提取器对象。请参阅http://www.scala-lang.org/node/112

object SEQ {
  def unapply[A](s:Seq[A]):Option[(A, Seq[A])] = {
    if (s.size == 0) None else {
      Some((s.head, s.tail))
    }
  }
}

def doMatch(seq: Seq[Int]) {
  seq match {
    case SEQ(head, Seq()) => println("final")
    case SEQ(head, tail) => {
      println("recursing")
      doMatch(tail)
    }
  }
}

I don't think there is pattern matching support for arbitrary sequences in the standard library. You could do it with out pattern matching though:

  def doMatch(seq: Seq[Int]) {
    if (seq.size == 1) println("final element " + seq(0)) else {
      println("recursing")
      doMatch(seq.tail)
    }
  }
  doMatch(1 to 10)

You can define your own extractor objects though. See http://www.scala-lang.org/node/112

object SEQ {
  def unapply[A](s:Seq[A]):Option[(A, Seq[A])] = {
    if (s.size == 0) None else {
      Some((s.head, s.tail))
    }
  }
}

def doMatch(seq: Seq[Int]) {
  seq match {
    case SEQ(head, Seq()) => println("final")
    case SEQ(head, tail) => {
      println("recursing")
      doMatch(tail)
    }
  }
}
彡翼 2024-12-02 23:34:27

从 Seq 到 List 的简单转换就可以完成这项工作:

def doMatch (list: List[Int]): Unit = list match {           
    case last :: Nil => println ("Final element.")             
    case head :: tail => println ("Recursing..."); doMatch (tail)
    case Nil => println ("only seen for empty lists") 
  }

def doMatchSeq (seq: Seq[Int]) : Unit = doMatch (seq.toList)

doMatch (List(3, 4, 5))
doMatchSeq (3 to 5)

A simple tranformation from Seq to List would do the job:

def doMatch (list: List[Int]): Unit = list match {           
    case last :: Nil => println ("Final element.")             
    case head :: tail => println ("Recursing..."); doMatch (tail)
    case Nil => println ("only seen for empty lists") 
  }

def doMatchSeq (seq: Seq[Int]) : Unit = doMatch (seq.toList)

doMatch (List(3, 4, 5))
doMatchSeq (3 to 5)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文