以下不起作用。
object Foo {
def union(s: Set[Int], t: Set[Int]): Set[Int] = t match {
case isEmpty => s
case (x:xs) => union(s + x, xs)
case _ => throw new Error("bad input")
}
}
错误:未找到:输入xs
如何在一组上进行模式匹配?
答案 0 :(得分:18)
好吧,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)
答案 1 :(得分:7)
Set
不是case class
,也没有unapply
方法。
这两件事意味着您无法直接在Set
上进行模式匹配
(更新:除非您为Set
定义自己的提取器,正如Daniel在答案中正确显示的那样)
您应该找到替代方案,我建议使用折叠功能
def union(s: Set[Int], t: Set[Int]): Set[Int] =
(s foldLeft t) {case (t: Set[Int], x: Int) => t + x}
或者,避免使用大多数显式类型注释
def union(s: Set[Int], t: Set[Int]): Set[Int] =
(s foldLeft t)( (union, element) => union + element )
甚至更短
def union(s: Set[Int], t: Set[Int]): Set[Int] =
(s foldLeft t)(_ + _)
这会累积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.
答案 2 :(得分: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")
}
}
答案 3 :(得分: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")
}
答案 4 :(得分:0)
t match {
case s if s.nonEmpty => // non-empty
case _ => // empty
}