2013-03-01 4 views

ответ

15

Ну, x:xs означает x типа xs, поэтому он не будет работать. Но, увы, вы не можете создавать сопоставления наборов, потому что наборы не имеют определенного порядка. Или, более прагматично, потому что нет экстрактора на Set.

Вы всегда можете определить свой собственный, хотя:

object SetExtractor { 
    def unapplySeq[T](s: Set[T]): Option[Seq[T]] = Some(s.toSeq) 
} 

Например:

scala> Set(1, 2, 3) match { 
    | case SetExtractor(x, xs @ _*) => println(s"x: $x\nxs: $xs") 
    | } 
x: 1 
xs: ArrayBuffer(2, 3) 
+3

Ницца. Чтобы быть понятным для Кевина: поскольку на наборах нет определенного порядка, вы должны * не * использовать SetExtractor с фактическими значениями, например. 'case SetExtractor (1, xs @ _ *) => ...'; он работает с 'Set (1,2,3)', но не будет работать вообще, например. с 'Set (1,2,3,4,5)'. Даниэль предлагает это как способ разрешить деконструкцию привязки для выбора произвольного элемента из набора. Также обратите внимание, что остаток, xs, является ArrayBuffer, поэтому, если вы хотите, чтобы он как набор использовал 'xs.toSet'. – AmigoNico

4

Прежде всего, ваш isEmpty поймает каждый Set, так как это переменная в этом контексте. Константы начинаются с буквы верхнего регистра в Scala и рассматриваются только как константы, если это условие выполняется. Поэтому в нижнем регистре будет назначать любой Set к isEmpty (вы искали EmptySet?)

Как видно here, кажется, что сопоставление с образцом не очень предпочтителен для Set с. Вы, вероятно, следует явно преобразовать Set к List или Seq (toList/toSeq)

object Foo { 
    def union(s: Set[Int], t: Set[Int]): Set[Int] = t.toList match { 
     case Nil => s 
     case (x::xs) => union(s + x, xs.toSet) 
     case _  => throw new Error("bad input") 
    } 
} 
+0

Там также backticked вещи которые также соответствуют стоимости. –

+0

есть ли какая-либо медлительность, связанная с преобразованием 'Set' в' List'? –

+0

Да. Вы можете использовать решение pagoda для повышения производительности. Я просто хотел показать вам, как это сделать с помощью сопоставления с образцом. Кстати, в моем примере случай '_' никогда не был достигнут – Danyel

5

Set не case class и не имеет метода unapply.

Эти две вещи подразумевают, что вы не можете сопоставлять соответствие непосредственно на Set.
(обновление: если вы не определить собственную экстрактор для Set, так как Даниэль правильно показывает в своем ответе)

Вы должны найти альтернативу, я предлагаю использовать кратную функцию

def union(s: Set[Int], t: Set[Int]): Set[Int] = 
    (s foldLeft t) {case (t: Set[Int], x: Int) => t + x} 

Это будет накапливать элементы s над t, добавляя их по одному


складного

Вот docs для кратных операций, если это необходимо для справки:

foldLeft[B](z: B)(op: (B, A) ⇒ B): B 

Применяется бинарный оператором начального значения и всех элементам этого множества, идя слева направо.

Примечание: могут быть возвращены разные результаты для разных прогонов, если не будет заказан базовый тип коллекции. или оператор ассоциативен и коммутативен.

B the result type of the binary operator. 
z the start value. 
op the binary operator. 
returns the result of inserting op between consecutive elements of this set, going left to right with the start value z on the left: 

op(...op(z, x_1), x_2, ..., x_n) 
where x1, ..., xn are the elements of this set. 
+0

, поэтому, если класс' Set' не имеет метода 'unappy()', то он не может быть разложен через совпадение? –

+1

Правильно, объект, который имеет метод 'unapply (...)', называется * extractor *, и его целью является определение способа извлечения его параметров в блоке 'match/case'. Это происходит автоматически для 'case classes'. Если возможно, вы должны увидеть * ch.26 * «Программирование в Scala 2nd ed.». для справки. –

1

Это то, что я могу придумать:

object Contains { 
    class Unapplier[T](val t: T) { 
    def unapply(s: Set[T]): Option[Boolean] = Some(s contains t) 
    } 
    def apply[T](t: T) = new Unapplier(t) 
} 

object SET { 
    class Unapplier[T](val set: Set[T]) { 
    def unapply(s: Set[T]): Option[Unit] = if (set == s) Some(Unit) else None 
    } 
    def apply[T](ts: T*) = new Unapplier(ts.toSet) 
} 

val Contains2 = Contains(2) 
val SET123 = SET(1, 2, 3) 

Set(1, 2, 3) match { 
    case SET123()   => println("123") 
    case Contains2(true) => println("jippy") 
    case Contains2(false) => println("ohh noo") 
} 
+0

также см .: [Кодирование в стиле: как владеть Скалой в окопах] (http://parleys.com/play/52a11b33e4b039ad2298ca78/chapter58/about) в 0:39:45 –

Смежные вопросы