【问题标题】:Understand 'case' keyword in partial functions理解部分函数中的“case”关键字
【发布时间】:2020-02-12 19:20:07
【问题描述】:

我是 Scala 的新手,我正在尝试解码它的结构,我了解了 pattern matching 并且语法类似于 Java switch 语句

val x: Int = Random.nextInt(10)

x match {
  case 0 => "zero"
  case 1 => "one"
  case 2 => "two"
  case _ => "other"
}

这里的代码非常明显且可读。我遇到了partial functions,它们非常明显并且很清楚它们是什么

偏函数是不提供答案的函数 可以给出每个可能的输入值。

我感到困惑的是在部分函数的主体中使用case 像这样:

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

我不明白在没有match 语句的情况下如何使用case,Scala 是如何解释它的,它是如何读取的,它是一个方法、一个类还是另一个构造?,我还有什么其他方法使用case 而不使用match 声明

编辑:

我试图玩弄这个案例,但仍然不明白。例如

val SomeFun: PartialFunction[Int, Int] = {
    case d: Int if d != 0 => 1000 / d
    case f: Int if f != 2 => 100 / f
    case m: Int if m != 1 => 10 / m
  }

这是如何工作的?

尝试这样做会出错

val SomeFun = {
    case d: Int if d != 0 => 1000 / d
    case f: Int if f != 2 => 100 / f
    case m: Int if m != 1 => 10 / m
  }


Error:(29, 17) missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ?

不匹配的大小写是否在偏函数之外的任何其他地方使用?

【问题讨论】:

    标签: scala pattern-matching partialfunction


    【解决方案1】:

    这意味着只有当输入参数可以匹配 case 表达式时才会应用偏函数。

    实际生成的类是这样的:

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

    使用 orElse 您可以应用或处理多个定义:

    funcForInt orElse funcForDouble orElse funcForString
    

    构图不错?

    编辑:

    val SomeFun: PartialFunction[Int, Int] = {
        case d: Int if d != 0 => 1000 / d
        case f: Int if f != 2 => 100 / f
        case m: Int if m != 1 => 10 / m
      }
    

    以上是使用匿名类功能。如果你删除变量的类型,你只是给它一个块表达式,其中包含一些编译器不能真正使用的 case 表达式。

    参考:https://www.james-willett.com/scala-anonymous-classes

    【讨论】:

    • 我了解它的工作原理,但我不了解应用或使用案例的语法
    • 以及这种情况如何转化为使用apply、被定义等等...
    【解决方案2】:

    我会试着回答这个问题:

    我不明白没有 match 语句如何使用 case,如何 这是由Scala解释的,它是如何读取的,它是一个方法,一个类 还是其他构造?

    主要参考this文章,我将引用和解释。

    这行得通的原因:

    val f: (Any) => String = {
        case i: Int => "Int"
        case d: Double => "Double"
        case _ => "Other"
    }
    

    是编译器将其解释为匿名函数。

    当你创建 val 函数时,你真正使用这样的代码所做的就是为匿名函数分配一个变量名。

    为了支持第一个语句,Scala 编程的第 15.7 节指出:

    花括号中的大小写序列可以在任何可以使用函数字面量的地方使用。

    所以它与在 filtercollect 内部使用相同的语法并没有真正的不同。

    上面的代码本质上创建了一个Function1 对象。正如this source 解释的那样:

    PartialFunction 和 scala.Function1 的主要区别是 PartialFunction 的用户可以选择做某事 与声明在其域之外的输入不同。

    【讨论】:

      【解决方案3】:

      这是the specification中描述的模式匹配匿名函数。

      尝试这样做会出错

      val SomeFun = ...
      

      这是因为需要知道参数类型,就像“普通”匿名函数 x => ... 一样。不同之处在于,在模式匹配匿名函数中,没有地方直接指定参数类型(相当于(x: Int) => ...),因此 必须 是预期的类型,例如val SomeFun: PartialFunction[Int, Int]val SomeFun: Int => Int

      val SomeFun: PartialFunction[Int, Int] = {
          case d: Int if d != 0 => 1000 / d
          case f: Int if f != 2 => 100 / f
          case m: Int if m != 1 => 10 / m
        }
      

      被翻译成

      val SomeFun: PartialFunction[Int, Int] = new PartialFunction[Int, Int] {
        override def apply(x: Int) = x match {
          case d: Int if d != 0 => 1000 / d
          case f: Int if f != 2 => 100 / f
          case m: Int if m != 1 => 10 / m
        }
        override def isDefined(x: Int) = x match {
          case d: Int if d != 0 => true
          case f: Int if f != 2 => true
          case m: Int if m != 1 => true
          case _ => false
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-05
        • 1970-01-01
        • 2013-02-28
        • 2014-12-03
        • 2016-03-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多