【问题标题】:How does isDefinedAt method work when case statements are used?使用 case 语句时 isDefinedAt 方法如何工作?
【发布时间】:2015-09-23 11:13:43
【问题描述】:

thisscala中偏函数的解释中,使用case语句如下:

val divide2: PartialFunction[Int, Int] = {
    case d: Int if d != 0 => 42 / d
}

然后它说:

虽然这段代码没有显式实现 isDefinedAt 方法,它的工作原理与前面的除法函数完全相同 定义

前面的divide函数明确定义apply和isDefined方法如下:

    val divide = new PartialFunction[Int, Int] {
    def apply(x: Int) = 42 / x
    def isDefinedAt(x: Int) = x != 0
}

我看到编译器在这里做了某种魔术,但我很好奇机制的本质:案例中的守卫(如果 d != 0)是否在后台提取到 isDefined 的主体中?有自己的警卫的多个案例陈述呢?函数的域是在 case 语句中定义的,因此这必须是编译器在幕后构建 isDefined 实现的方式。

我说的对吗?

【问题讨论】:

    标签: scala partialfunction


    【解决方案1】:

    首先,解释是错误的,因为两个示例的工作方式不同:

    scala> val a: PartialFunction[Int, Int] = {
         | case i if i != 0 => 42 / i
         | }
    a: PartialFunction[Int,Int] = <function1>
    
    scala> val b = new PartialFunction[Int, Int] {
         | def apply(i: Int) = 42 / i
         | def isDefinedAt(i: Int) = i != 0
         | }
    b: PartialFunction[Int,Int] = <function1>
    
    scala> a(0)
    scala.MatchError: 0 (of class java.lang.Integer)
      at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:253)
      at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:251)
      at $anonfun$1.applyOrElse(<console>:7)
      at $anonfun$1.applyOrElse(<console>:7)
      at scala.runtime.AbstractPartialFunction$mcII$sp.apply$mcII$sp(AbstractPartialFunction.scala:36)
      ... 33 elided
    
    scala> b(0)
    java.lang.ArithmeticException: / by zero
      at $anon$1.apply$mcII$sp(<console>:8)
      ... 33 elided
    

    但它的核心是真的,编译器将case子句中的代码转换为isDefinedAt方法的布尔表达式,然后将函数本身作为apply方法(因此如果未定义值,则MatchError)

    举个一般的例子,这样的函数:

    val a = PartialFunction[A, B] {
        case <clause A> => <action A>
        case <clause B> => <action B>
    }
    

    编译为:

    val a = new PartialFunction[A, B] {
        def isDefinedAt(a: A) = a match {
            case <clause A> => true
            case <clause B> => true
            case _ => false
        }
        def apply(a: A) = a match {
            case <clause A> => <action A>
            case <clause B> => <action B>
        }
    }
    

    这是定义此行为的spec

    【讨论】:

    • 感谢规范的链接
    【解决方案2】:

    我相信它可以正常工作,因为模式匹配定义支持可用的case

    divide2 方法有一个匹配的情况:x != 0 给定了 Int 类型的 x,因此,如果您的值不是这样,它应该返回 false。

    【讨论】:

      猜你喜欢
      • 2018-11-15
      • 2016-06-27
      • 1970-01-01
      • 1970-01-01
      • 2012-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-13
      相关资源
      最近更新 更多