сопоставление шаблона возвращает другой результат для ArrayBuffer и Seq

В приведенном ниже примере есть функция seqResult, которая соответствует шаблону Seq. Другая функция, которая принимает переменные аргументы, вызывает seqResult и передает ArrayBuffer. Это приводит к тому, что результат сопоставления с образцом будет другим при вызове с Seq или с ArrayBuffer.

С Seq сопоставитель находит case head :: rest => ..., с ArrayBuffer сопоставляет case Seq(one, two) => ....

Это ошибка? Можно ли как-то защититься от этого?

Если это не ошибка, как можно безопасно сопоставить список из 1 или более записей, которые будут работать для Seq(a,b) и ArrayBuffer(a,b)?

def seqResult(arr:Seq[String]) = arr match {
  case Nil =>  "Nil"
  case head :: Nil => "head :: Nil"
  case head :: rest => "head :: rest"
  case Seq(one, two) => "one, two"
  case _ => "other"
}

def varArgResult(args:String*) = seqResult(args)

val ab = varArgResult("one", "two")
val se = seqResult(Seq("one", "two"))

println(ab) //=> "one, two"
println(se) //=> "head :: rest"

person ed.    schedule 01.03.2016    source источник


Ответы (2)


:: — объект экстрактора для Lists. Поскольку списки являются реализацией Seq по умолчанию, это то, что вы видите при использовании Seq(a, b, ...).

Извлекателем для Seqs является +:.

person badcook    schedule 01.03.2016
comment
Привет - то, что я искал - person ed.; 01.03.2016

args: String* на самом деле Array

Seq() конструктор использует конструктор на основе ListBuffer, поэтому в результате мы имеем List тип данных.

object Seq extends SeqFactory[Seq] {
  def newBuilder[A]: Builder[A, Seq[A]] = new mutable.ListBuffer
}

...

println(Seq("one", "two"))

List(one, two)

head::rest является синтаксическим сахаром для сопоставления List и может быть представлено как List(head, rest), что соответствует se в вашем случае.

person vvg    schedule 01.03.2016
comment
только что добавил последний вопрос - какой вариант лучше всего подходит в этом случае? - person ed.; 01.03.2016