【问题标题】:How to know when to use PartialFunction vs return Option如何知道何时使用 PartialFunction vs return Option
【发布时间】:2014-09-29 07:47:42
【问题描述】:

例如,我们定义了一个函数,应该将 1、3、42 分别转换为 "foo"、"bar"、"qix" 和所有其他整数到 "X"。

我提出了 2 个实现: 方法f 需要分开,因为它可以在其他上下文中重用。

def f(i: Int): Option[String] = i match {
  case 1 => Some("foo")
  case 3 => Some("bar")
  case 42 => Some("qix")
  case _ => None
}

def g(i: Int) : String = f(i).getOrElse("X")

还有:

def f_ : PartialFunction[Int, String] = {
  case 1 => "foo"
  case 3 => "bar"
  case 42 => "qix"
}

def g_(i: Int) : String = f_.orElse { case _ => "X" }(i)

我更喜欢第二种,因为它避免了许多重复的 Some(...)

WDYT ?

【问题讨论】:

  • 没有人说你必须在比赛中使用Some
  • 请注意,您可以解除部分功能。在你的情况下f_.lift == f

标签: scala partial-functions


【解决方案1】:

当您可以轻松地执行此操作并获得完全相同的结果时,我完全不确定您为什么要使用选项:

def f(i: Int): String = i match {
  case 1  => "foo"
  case 3  => "bar"
  case 42 => "qix"
  case _  => "X"
}

它甚至可以为您省去讨厌的getOrElse

您甚至可以做得更好,既不使用PartialFunction 也不使用match,只需这样做:

def f: Int => String = {
  case 1  => "foo"
  case 3  => "bar"
  case 42 => "qix"
  case _  => "X"
}

这样可以节省您编写一次性i

【讨论】:

    【解决方案2】:

    fScala 的 Map 已经是一个偏函数。因此,您可以使用它而不是定义自己的函数,该函数完全符合 Map 的功能 - “从 A 类型的键映射到 B 类型的值”。
    所以你所要做的就是:

    val f = Map(1 -> "foo", 3 -> "bar", 42 -> "qix")
    def g(i: Int) = f.getOrElse(i, "X")
    
    f(1)  //foo
    f(4)  // throw NoSuchElementException: Key not found: 4
    f.get(1) // Some(foo)
    f.get(4) // None
    g(1)  //foo
    g(4)  //X
    

    现在您可以使用函数“g”或将“f”重用于其他需求。

    【讨论】:

      【解决方案3】:

      根据您的评论编辑了我的示例:

      def f(i: Int): Option[String] = {
        val map = Map(1 -> "foo", 3 -> "bar", 42 -> "qix")
        i match {
          case x if (map.contains(x)) => Some(map(x))
          case _ => None
        }
      }
      
      def g(i: Int) : String = f(i).getOrElse("X")
      

      我认为该函数应该以某种有意义的方式对给定范围之外的整数做出反应。这就是为什么我更喜欢Option

      【讨论】:

      • 我已经编辑了我的问题,在我的实际案例中它不一定是一个范围。
      • @YannMoisan 下次请提供完整的上下文。我回答了您的原始问题,然后您对其进行了修改。然后我回答了修改后的问题,现在你又修改了。我会回答您的问题,但如果您每次我提供答案时提出不同的要求,我也无能为力。
      • @YannMoisan 我再次修改了我的答案。但这应该足够了。
      【解决方案4】:

      Option 是处理空值的好方法。 部分函数只是部分匹配,它们并不相同,尽管Option和PartialFunction都有类似的orElse方法

      由于partial function是一个function,所以可以链式但是option不能,Option是处理空值的方式。

      对于你可以这样做的部分功能,它更像是责任链

      def f_1 : PartialFunction[Int, String] = {
        case 1 => "1"
      }
      
      def f_2 : PartialFunction[Int, String] = {
        case 2 => "2"
      }
      
      def f_3 : PartialFunction[Int, String] = {
        case 3 => "3"
      }
      
      f_1.orElse(f_2).orElse(f_3)(3)
      

      【讨论】:

        【解决方案5】:

        您可能想试试这个。这里 HashMap 可以让你快速查找:

        object SomeMain {
          import scala.collection.immutable.HashMap
          def f(i: Int): Option[String] = {
            HashMap(1 -> "foo", 3 -> "bar", 42 -> "qix").get(i).orElse(None)
          }
        
          def g(i: Int): String = f(i).getOrElse("X")
        
          def main(args: Array[String]) {
            List(1, 3, 42, 10) foreach { x => println(x + ": " + g(x)) }
          }
        }
        

        输出:

        1: foo
        3: bar
        42: qix
        10: X
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-12-26
          • 2019-08-07
          • 1970-01-01
          • 1970-01-01
          • 2012-01-10
          • 1970-01-01
          • 1970-01-01
          • 2020-02-18
          相关资源
          最近更新 更多