4

是否有对返回结果的断言的内置支持?

这样做是非常无效的:

  def addPositive(a: Int, b: Int) = {
    assert(a > 0 && b > 0)
    a + b
  }

我宁愿做类似的事情:

  def addPositive(a: Int, b: Int) = 
    assert(a > 0 && b > 0)(a + b)

通过这种方式,我可以避免断言的命令性方面。(后者不编译)有类似的东西吗?

4

3 回答 3

15

函数式编程将函数视为纯数学函数(理想情况下)。那么数学上说一个函数对某些参数不起作用并且必须爆炸的方式是什么?

偏函数

事实证明,Scala 对这个概念有很好的支持:PartialFunction。这是使用部分函数重写代码的方式:

val addPositive: PartialFunction[(Int, Int), Int] = {
  case (a, b) if a > 0 && b > 0 => a + b
}

这有几个好处:

如果您使用错误的参数调用它,它将引发MatchError异常。

addPositive(-1, 2) => Exception in thread "main" scala.MatchError: (-1,2) (of class scala.Tuple2$mcII$sp)

您实际上可以对函数的域进行采样,以检查某些值是否非常适合作为函数的参数:

addPositive.isDefinedAt(-1, 2) => false

如果您想将该函数应用于某些参数并获得一个结果或某个指示失败的值,您可以lift将其返回Option

addPositive.lift(-1, 2) => None
addPositive.lift(1, 2) => Some(12)

您可以将其与其他函数组合,以在参数无效的情况下提供回退:

val fallback: PartialFunction[(Int, Int), Int] = { case (a, b) => Int.MinValue }
val f = addPositive orElse fallback

f(-1, 2) => -2147483648

或者以自定义方式处理错误:

val raiseError: PartialFunction[(Int, Int), Int] = {
  case (a, b) => throw new IllegalArgumentException(s"Cannot apply addPositive to arguments $a and $b")
}
val g = addPositive orElse raiseError

g(-1, 2) => Exception in thread "main" java.lang.IllegalArgumentException: Cannot apply addPositive to arguments -1 and 2

它适用于标准库:请参阅Seq.collectSeq.collectFirst.

也是PartialFunction一个普通的一元函数,所以你也继承了所有的函数操作。

这是一篇文章,非常优雅地解释了 Scala 中的偏函数:

Scala 部分函数(没有博士学位)

于 2013-04-12T12:58:42.067 回答
4

您可以推出自己的实现:

def assert[T](cond: =>Boolean)(expr: =>T): T = {
  assert(cond)
  expr
}

您还可以使用选项类型来避免异常,但这意味着您稍后必须对结果进行模式匹配:

def addPositive(a: Int, b: Int): Option[int] =
  if (a > 0 && b > 0) Some(a + b)
  else None

这可以以与上述assert变体类似的方式重构。

于 2013-04-12T11:43:41.553 回答
-5

require前置条件的功能,它几乎可以完成你想要的。你可以做

def addPositive(a: Int, b: Int) = 
   require (a > 0 && b > 0, a + b)

有一部分scala.Predef,所以它们总是被包括在内。参数(a+b在示例中)是按名称传递的,因此只有在条件不成立时才会执行。

requires始终处于激活状态,如果您希望能够停用它,您也可以使用它assert,例如:

assert(a > 0 && b > 0, a + b)
于 2013-04-12T12:24:40.063 回答