了解部分功能中的“ case”关键字

时间:2019-10-16 05:02:11

标签: scala pattern-matching partialfunction

我是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 ?! 
}

我不理解没有case语句的情况下如何使用match,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: ?

不匹配的情况是否在部分函数之外的其他任何地方使用?

4 个答案:

答案 0 :(得分:5)

这意味着仅当输入参数可以匹配大小写表达式时,才会应用部分函数。

生成的实际类如下:

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表达式的块表达式,而这些case表达式是编译器无法真正使用的。

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

答案 1 :(得分:2)

我将尝试回答这个问题:

  

我不了解没有match语句时如何使用大小写,怎么办   它由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的用户可以选择做某事   与声明在其域外的输入有所不同。

答案 2 :(得分:1)

这是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
  }
}

答案 3 :(得分:0)

编译器翻译

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

类似于

def divide(d: Int) = {
  if (d != 0)
    42 / d
  else
    throw new MatchError(d)
}

回答

  

...我可以在没有case语句的情况下使用match的其他方式

问自己一个问题,我们可以在哪里使用翻译后的def版本。请注意,PartialFunction定义如何具有不安全 throw,这是要记住的重要方面。

作为一个旁注,使用case子句定义函数与数学中的piecewise function定义相似。