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