嵌套/内部变量范围

时间:2012-11-29 17:37:31

标签: scala scope

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)

2 个答案:

答案 0 :(得分: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!!!!

答案 1 :(得分:1)

块不会改变外部变量本身的可见性。只有在内部范围内声明具有相同名称的变量时,Odersky引用才会解释。

前两个示例不执行此操作,因此外部变量在内部范围内明显可见,而Odersky的引用不适用。内部范围中的a与外部范围中的a相同,不涉及复制。

然而,在第三个示例中,两个a是两个独立的val变量,即内部a不是重新定义外部{{1}根据Odersky的引用,只是 shadowing ,例如:

a

即。退出内部块后,您会看到外部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语句所引用的变量),则很难做出决定。我手头没有确切的参考,但我相信编译器不允许这样的代码,因为这种风格本身就不容易出错,而且本身就容易出错。