programing

목록 이외의 시퀀스에 대한 스칼라 패턴 일치

nicescript 2021. 1. 17. 10:35
반응형

목록 이외의 시퀀스에 대한 스칼라 패턴 일치


List 내의 각 요소에서 재귀 적으로 작동하는 다음 코드가 있습니다.

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에서 일치 시키려고하면 컴파일러가 'error : not found : value + :'라고 불평합니다.
  • 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의 대답은 ::가 내 예제에서 연산자가 아니라 케이스 클래스이므로 차이가 있다는 것을 언급 한 첫 번째 사람 이었기 때문입니다.


::Scala 에는 두 가지 (단점으로 발음 됨)가 있습니다. 하나는에 정의 된 연산자 class List이고 다른 하나는 머리와 꼬리가 특징 인 비어 있지 않은 목록을 나타내는 클래스 (의 하위 클래스 List)입니다.

head :: tail에서 구문 상 수정 된 생성자 패턴입니다 ::(head, tail).

:: 케이스 클래스입니다. 이는 이에 대해 정의 된 추출기 오브젝트가 있음을 의미합니다.


일종의 속임수이지만 여기에 있습니다.

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*작동 하지 않는지 묻지 마세요 ...


2012 년 3 월의 ides 현재 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.

더 일반적으로, 두 개의 서로 다른 헤드 / 테일 및 초기화 / 마지막 분해는 객체 미러링 APPEND / 앞에 추가 추가되었다 Seq에서 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)

실제로 +:원하는 것을 정확히 수행 하기 위해 객체를 정의 할 수 있습니다 .

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


표준 라이브러리에서 임의의 시퀀스에 대한 패턴 일치 지원이 없다고 생각합니다. 하지만 패턴 매칭없이 할 수 있습니다.

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

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)

ReferenceURL : https://stackoverflow.com/questions/6807540/scala-pattern-matching-on-sequences-other-than-lists

반응형