3

我正在学习 scala,作为最好的培训,我正在将旧的 Java 算法转换为函数式编程风格。我有以下代码:

def test(originalSet: Set[Int]):Boolean = originalSet match {
    case Set()  => true
    case x::y => false
  } 

此代码适用于 Lists,但对于 Sets,它会给我以下编译错误:

  - value Set is not a case class constructor, nor does it have an unapply/unapplySeq 
         method

- constructor cannot be instantiated to expected type; found : scala.collection.immutable.::[B] required: 
     scala.collection.immutable.Set[Int]
    - constructor cannot be instantiated to expected type; found : scala.collection.immutable.::[B] required: 
     scala.collection.immutable.Set[Int]

问题是什么?如何测试 Set 为空的情况?当 set 有头部和尾部时,我该如何处理?

4

3 回答 3

7

Set定义一个isEmpty方法,所以最简单的解决方案是

def test(originalSet: Set[Int]): Boolean = originalSet.isEmpty

当您使用与列表匹配时

list match {
    case Nil => true
    case x :: y => false
}

Nil您正在与 List对象和类进行匹配,::即它相当于

list match {
    case Nil => true
    case ::(x, y) => false
}

因此,您不能将此表单与Set.

当您使用以下方式对 List 进行模式匹配时:

list match {
    case List(a, b) => true
    case _ => false
}

您正在使用列表提取器。如果列表具有给定格式,则List使用哪个匹配项定义提取器。没有定义or方法,所以你也不能以这种方式匹配它。unapplySeqSetunapplyunapplySeq

于 2013-09-08T20:05:39.073 回答
3

这个问题有点老了,但令我惊讶的是,没有一个答案给出了允许模式匹配的解决方案。

为了保留Set语义并能够进行模式匹配,您将需要实现一个接受for 输入的自定义unapply方法。Set这是一个非常有用的模式,几乎可以应用于任何类型。

object EmptySet {
  def unapply[A](s: Set[A]): Boolean = s.isEmtpy
}

object NonEmptySet {
  def unapply[A](s: Set[A]): Option[Set[A]] = 
    if (s.isEmpty) None
    else Some(s)
}

def foo(bars: Set[Int]): String = bars match {
  case EmptySet => "No Bars"
  case NonEmptySet(values) => s"Bars: $values"
}

此处描述了该模式:http: //docs.scala-lang.org/tutorials/tour/extractor-objects.html

于 2016-04-21T17:57:38.593 回答
2

Set 没有 unapply 方法,也没有 Seq,因此在它们上使用 case 解构器没有多大意义。(参考Scala Pattern Matching with Sets).. 但是我会添加我自己的注释,我一直在学习 scala,最初认为大小写匹配应该用于所有事情 - 但在函数式编程中使用 if-then 语句是完全可以接受的,并且在这里最有意义。

def test(originalSet: Set[Int]):Boolean = ! originalSet.isEmpty
于 2013-09-08T20:08:38.547 回答