7

我在网上遇到错误:

case Sum(l, r) => printExpr(l); print("+"); printExpr(r)

错误是:

递归方法 printExpr 需要结果类型

这段代码对我来说看起来不错,我做错了什么?

abstract class Expr {

  case class Num(n: Int) extends Expr
  case class Sum(l: Expr , r: Expr) extends Expr
  case class Prod(l: Expr, r: Expr) extends Expr

  def evalExpr(e: Expr): Int = e match {
    case Num(n) => n
    case Sum(l, r) => evalExpr(l) + evalExpr(r)
    case Prod(l, r) => evalExpr(l) * evalExpr(r)
  }

  def printExpr(e: Expr) = e match {
    case Num(n) => print(" " + n + " ")
    case Sum(l, r) => printExpr(l); print("+"); printExpr(r)
    case Prod(l, r) => printExpr(l); print("x"); printExpr(r)
  }
}
4

3 回答 3

12

正如错误消息所述,Scala 中的递归方法需要明确声明的返回类型。

原因是 Scala 从方法体中使用的类型推断方法的返回类型。当方法的返回类型影响方法体中使用的类型时(因为它递归地调用自身),Scala 无法确定它应该分配给方法的类型,因此它要求您在源代码中这样做(就像你有的evalExpr,你明确地说它返回一个Int)。

在这种情况下,您希望printExpr有 return type Unit,这是没有信息的无趣值的类型。通常调用具有返回类型的方法Unit只是为了它的副作用(例如print)。

因此,您可以将标题行更改printExpr为:

def printExpr(e: Expr) : Unit = e match {

或者,Scala 有一些用于声明“过程”的语法糖。您可以将“过程”视为不返回任何内容,只是执行一些代码,但实际上 Scala 中的每个方法都会返回一些内容;“过程”只是返回类型的方法Unit。这样做的语法是=在方法的标头之后省略,但是您必须用花括号将方法主体括起来(即使它是单个表达式,例如您的match)。所以你可以这样做:

def printExpr(e: Expr) {
  e match {
    ...
  }
}

避免明确声明Unit.

于 2012-11-06T22:20:23.173 回答
4

Scala 编译不能为递归方法推断类型,因此您必须显式声明它:

def printExpr(e: Expr): Unit = e match {
于 2012-11-06T22:21:13.763 回答
1

给一个返回类型printExpr(e : Expr)喜欢StringExpr例如

printExpr(e : Expr): Expr
printExpr(e : Expr): String
于 2012-11-06T22:21:07.693 回答