【问题标题】:How does PartialFunction deal with undefined values in Scala?PartialFunction 如何处理 Scala 中的未定义值?
【发布时间】:2015-12-24 08:53:49
【问题描述】:

我在 Scala 中定义了两个版本的PartialFunction

  val doubleEvens1: PartialFunction[Int, Int] = {
    case x if x % 2 == 0 => x * 2
  }

  val doubleEvens2 = new PartialFunction[Int, Int] {
    override def isDefinedAt(x: Int): Boolean = x % 2 == 0

    override def apply(v1: Int): Int = v1 * 2
  }

还有一个清单:

val list = List(1, 2, 3, 4, 5)

但是,对于未定义的值,它们的行为会有所不同:

// doubleEvens1
println(doubleEvens1.isDefinedAt(3)) // false
println(list.collect(doubleEvens1))  // List(4, 8)
println(doubleEvens1(3))             // scala.MatchError
println(list.map(doubleEvens1))      // scala.MatchError

// doubleEvens2
println(doubleEvens2.isDefinedAt(3)) // false
println(list.collect(doubleEvens2))  // List(4, 8)
println(doubleEvens2(3))             // 6
println(list.map(doubleEvens2))      // List(2, 4, 6, 8, 10)

我猜doubleEvens1应该是合理的,因为它符合数学定义。但是doubleEvens2 的行为是故意设计的吗?还是我在代码 sn-p 中遗漏了什么?

【问题讨论】:

    标签: scala functional-programming


    【解决方案1】:

    如果您实现自己的apply 方法并且不检查isDefinedAt,那么显然您可以使用任何输入调用该方法而不会引发异常。这在文档中明确说明:

    在调用apply之前调用isDefinedAt是调用者的责任,因为如果isDefinedAt为假,则不能保证apply会抛出异常来指示错误情况。如果没有抛出异常,评估可能会产生任意值。

    碰巧从模式匹配创建的部分函数从其apply方法实现中调用isDefinedAt本身并抛出异常。

    因此,如果您想复制该行为,则必须这样做:

    val doubleEvens2 = new PartialFunction[Int, Int] {
      override def isDefinedAt(x: Int): Boolean = x % 2 == 0
    
      override def apply(x: Int): Int = 
        if (isDefinedAt(x)) x * 2 else throw new MatchError(x.toString)
    }
    

    当然,缺点是某些代码 (isDefined) 可能会被多次调用,如 this question 中所述。

    【讨论】:

    • 刚刚注意到有几个帖子没有明确说明这个问题,并在没有isDefinedAt 保护的情况下定义了他们的PartitionFunctions'apply。无论如何,我应该在问这个问题之前阅读文档;对不起。
    • 文档说您可以定义 apply 而不定义 isDefinedAt。简单来说,如果使用站点不检查isDefinedAt,则apply 的行为是未定义的。使用诸如 collect 之类的带有部分函数的集合方法将检查 isDefined (如示例调用的每一行所示)。因为PartialFunctionFunction 的子类型,您可能会遇到奇怪的情况,例如List.map,它不知道您正在使用偏函数,因此不调用isDefinedAt
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-07
    相关资源
    最近更新 更多