首页 > 解决方案 > scala:匹配情况下的“块不能包含声明”

问题描述

我有以下函数,它给了我错误:块不能包含声明这段代码有什么问题?

def max[A](tree: Tree[A])(func: (A, A) => Int): A = tree match {
    case Leaf(value) => value
    case Branch(value, left, right) => {
      val leftMax = max(left)(func)
      val rightMax = max(right)(func)
      var currMax: A // block cannot contain declarations
      if (func(leftMax, rightMax) > 0) {
        currMax = leftMax
      } else {
        currMax = rightMax
      }

      if (func(value, currMax) > 0) {
        currMax = value
      }
      currMax
    }
}

标签: scala

解决方案


考虑声明定义的区别

var x: Int       // declaration: variable named x is of type Int
var x: Int = 42  // definition:  variable named x is of type Int and refers to value 42

请注意,纯声明如何简单地说明变量的类型,但没有说明它的值。另一方面,定义既是一种声明又是将一个具体的值与变量相关联。我们可以在特征或抽象类中使用纯声明,例如,

trait Foo {
  var x: Int // pure declaration
}

object MyFoo extends Foo {
  override var x: Int = 42
}

但是我们不能将它们放在块表达式中,例如

{
  var x: Int    // error: only traits and abstract classes can have declared but undefined members
  "hello world"
}

说明声明和定义之间的区别,考虑当我们声明变量时在字节码级别会发生什么x

scala> trait Foo { val x: Int }
defined trait Foo

scala> :javap -c -filter Foo
Compiled from "<console>"
public interface Foo {
  public abstract int x();
}

与我们定义变量时相比x

scala> trait Foo { val x: Int = 42 }
defined trait Foo

scala> :javap -c -filter Foo
Compiled from "<console>"
public interface Foo {
  public abstract void $line4$$read$Foo$_setter_$x_$eq(int);

  public abstract int x();

  public static void $init$(Foo);
    Code:
       0: aload_0
       1: bipush        42
       3: invokeinterface #23,  2           // InterfaceMethod $line4$$read$Foo$_setter_$x_$eq:(I)V
       8: return
}

注意在声明的情况下没有生成代码指令,而在定义的情况下有实际的指令,例如bipush 42. 因此,声明只是编译器感兴趣的东西,而定义也会导致具体的运行时内存操作。


推荐阅读