【问题标题】:Scala Set match caseScala 设置匹配案例
【发布时间】:2016-04-22 21:24:57
【问题描述】:

我正在学习 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 有头部和尾部时,我该如何处理?

【问题讨论】:

  • Test 对于该代码来说是一个非常糟糕的名称 - 为什么不将其命名为 isEmpty?

标签: scala functional-programming


【解决方案1】:

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

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

当您使用列表匹配时

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

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

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

因此您不能将此表单与Set 一起使用。

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

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

您正在使用列表提取器。 List 提取器使用unapplySeq 定义,如果列表具有给定格式,则匹配。 Set 没有定义 unapplyunapplySeq 方法,所以你也不能这样匹配。

【讨论】:

    【解决方案2】:

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

    为了保留Set 语义并能够进行模式匹配,您需要实现一个自定义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

    【讨论】:

    • NonEmptySet 应该有两个参数,选择单个元素和剩余的(可选为空)集合。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-13
      • 2017-02-25
      • 2018-10-03
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 2020-10-04
      相关资源
      最近更新 更多