学习Scala的变量范围
创始人
2024-04-18 22:21:46
0

现在你已经看过了Scala的内建控制结构,我们将在本节中使用它们来解释Scala里的范围是如何起作用的。

51CTO编辑推荐:Scala编程语言专题

Scala程序里的变量定义有一个能够使用的范围:scope。范围设定的最普通不过的例子就是,大括号通常引入了一个新的范围,所以任何定义在打括号里的东西在括号之后就脱离了范围。这条规则有几个例外,因为在Scala里有时候你可以用大括号代替小括号。表达式语法的替代品是这种使用大括号例子的其中之一。作为演示,请看一下代码7.18里展示的函数:

  1. def printMultiTable() {  
  2.   var i = 1 
  3.   // 这里只有i在范围内  
  4.   while (i <= 10) {  
  5.     var j = 1 
  6.     // 这里i和j在范围内  
  7.     while (j <= 10) {  
  8.       val prod = (i * j).toString  
  9.       // 这里i,j和prod在范围内  
  10.       var k = prod.length  
  11.       // 这里i,j,prod和k在范围内  
  12.       while (k < 4) {  
  13.         print(" ")  
  14.         k += 1 
  15.       }  
  16.       print(prod)  
  17.       j += 1 
  18.     }  
  19.     // i和j仍在范围内;prod和k脱离范围  
  20.     println()  
  21.     i += 1 
  22.   }  
  23.   // i仍在范围内;j,prod和k脱离范围  
  24. }  
代码 7.18 打印乘法表时的变量范围

printMultiTable函数打印了乘法表。 函数的第一个语句引入了变量i并初始化为整数1。然后你可以在函数余下的部分里使用名称i。

printMultiTable接下去的语句是一个while循环:

  1. while (i <= 10) {  
  2.   var j = 1 
  3.   ...  
  4. }  
你可以在这使用i因为它仍在范围内。在while循环的第一个语句里,你引入了另一个变量,叫做j,并再次初始化为1。因为变量j定义在while循环的大括号内,所以只能用在while循环里。如果你想尝试在while循环的大括号之后,在那个说j,prod和k已经出了范围的注释后面,再用j做点儿什么事,你的程序就编译不过了。

本例中定义的所有变量——i,j,prod和k——都是本地变量:local variable。对于它们被定义的函数来说是“本地”的。每次函数被调用的时候,一整套全新的本地变量将被使用。

一旦变量被定义了,你就不可以在同一个范围内定义同样的名字。比如,下面的脚本不会被编译通过:

  1. val a = 1 
  2. val a = 2 // 编译不过  
  3. println(a)  
然而,你可以在一个内部范围内定义与外部范围里名称相同的变量。下列脚本将编译通过并可以运行:

  1. val a = 1;  
  2. {  
  3.   val a = 2 // 编译通过  
  4.   println(a)  
  5. }  
  6. println(a)  
执行时,这个脚本会先打印2,然后打印1,因为定义在内部打括号里的a是不同的变量,将仅在大括号内部有效。另外,本例中在a的第一个定义之后需要加分号,因为Scala的分号推断机制不会在这里加上分号。Scala和Java间要注意的一个不同是,与Scala不同,Java不允许你在内部范围内创建与外部范围变量同名的变量。在Scala程序里,内部变量被说成是遮蔽:shadow了同名的外部变量,因为在内部范围内外部变量变得不可见了。

或许你已经注意到了一些在解释器里看上去像是遮蔽的东西:

  1. scala> val a = 1 
  2. a: Int = 1 
  3. scala> val a = 2 
  4. a: Int = 2 
  5. scala> println(a)  
解释器里,你可以对你的核心内容重用变量名。撇开别的不说,这样能允许你当发现你在解释器里第一次定义变量时犯了错误的时候改变主意。你能这么做的理由是因为,在理论上,解释器在每次你输入新的语句时都创建了一个新的嵌套范围。因此,你可以把之前解释的代码虚拟化认为是:

  1. val a = 1;  
  2. {  
  3.  var a = 2;  
  4.  {  
  5.   println(a)  
  6.  }  
  7. }  

这段代码可以像Scala脚本那样编译和执行,而且像输入到解释器里的代码那样,打印输出2。请记住这样的代码对读者来说是很混乱的,因为在嵌套范围中变量名称拥有了新的涵义。通常更好的办法是选择一个新的有意义的变量名而不是遮蔽外部变量。

【相关阅读】

  1. Scala:match表达式、break和continue
  2. 学习Scala:使用try-catch表达式处理异常
  3. Scala中的for表达式:枚举的“瑞士军刀”
  4. Scala中的if表达式和while循环
  5. 学习Scala的重载方法和隐式转换

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...