1

Scala 中有关变量的范围的确切处理是什么?

当我打开大括号时,我仍然可以访问外部变量的值(如果是变量,则修改它们):

scala> var mmm = 4
mmm: Int = 4

scala> {
     | println(mmm)
     | mmm += 2
     | println(mmm)
     | }
4
6

scala> println(mmm)
6

但是奥德斯基在第 180 页或他的书中说

在 Scala 程序中,内部变量被称为遮蔽了同名的外部变量,因为外部变量在内部范围内变得不可见。

这似乎更奇怪:

scala> val a = 4
a: Int = 4

scala> {
     | println(a)
     | }
4

那么我是否可以获得在内部范围内创建的副本?

scala> val a = 4
a: Int = 4

scala> {
     | val a = 8
     | }

如果 val 是不可变的,为什么我还要再说一遍?

scala> val a = 4
a: Int = 4

scala> {
     | println(a)
     | val a = 8
     | println(a)
     | }

但是对于这个我得到一个错误:

error: forward reference extends over definition of value a
              println(a)
4

2 回答 2

5

如果您在块中创建一个新的,则新的会影响旧的(外部)。如果你不这样做,你指的是外部的。

在块中创建新块的位置无关紧要。如果它出现在任何地方,它会遮蔽外部。

所以,

val a = 5
{ println(a) }  // This is outer a

val a = 5
{ val a = 8; println(a) }  // This is inner a

val a = 5
{ println(a); val a = 8 }  // This is broken
                           // you try to print the inner a
                           // but it doesn't exist yet

编辑:让我们打开最后一个

val a = 5
// Okay, I have something called a

{  // Oh, new block beginning!  Maybe there are local variables
  println(a)
  val a = 8    // Yeah, there's one!
               // And it's got the same name as the outer one
               // Oh well, who needs the outer one anyway?
}

// Waitaminute, what was that block supposed to do?
{
  println(a)   // Inner block has an a, so this must be the inner a
  val a = 8    // Which is 8
}

// Hang on, operations happen in order
{
  println(a)   // What inner a?!

// Abort, abort, abort!!!!
于 2012-11-29T17:44:24.247 回答
1

块本身不会改变外部变量的可见性。仅当您在内部范围内声明具有相同名称的变量时,正如 Odersky 引用所解释的那样。

您的前两个示例没有这样做,因此外部变量在内部范围内是显而易见的,并且 Odersky 的引用不适用。内部a作用域中的 与外部作用域中的 相同a,不涉及复制。

然而,在第三个示例中,两个as 是两个自val变量,即 innera没有重新定义external a,只是按照 Odersky 的引用对其进行了遮蔽,例如:

val a = 4
println(a)  // prints 4 - outer a
{
  val a = 8;
  println(a)  // prints 8 - inner a
}
println(a)  // prints 4 - outer a in scope again

即退出内部块后,您会看到a具有原始值的外部块仍然存在。

但是,您在第三个示例中显示的代码非常模棱两可,因为如果不深入了解语言规范,就很难确定您的第一条println(a)语句所指的变量是哪个变量。我手头没有确切的参考资料,但我相信编译器不允许这样的代码,因为这种风格没有任何好处,而它本身就容易出错。

于 2012-11-29T17:44:03.703 回答