Scala编程实例:带类型的参数化数组

Scala里可以使用new实例化对象或类实例。当你在Scala里实例化对象,可以使用值和类型把它参数化:parameterize。参数化的意思是在你创建实例的时候“设置”它。通过把加在括号里的对象传递给实例的构造器的方式来用值参数化实例。

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

例如,下面的Scala代码实例化一个新的java.math.BigInteger并使用值"12345"参数化:

val big = new java.math.BigInteger("12345") 

通过在方括号里设定一个或更多类型来参数化实例。代码3.1里展示了一个例子。在这个例子中,greetStrings是类型Array[String](字串数组)的值,并被第一行代码里的值3参数化,使它的初始长度为3。如果把代码3.1里的代码作为脚本执行,你会看到另一个Hello, world!的祝词。请注意当你同时用类型和值去参数化实例的时候,类型首先在方括号中出现,然后跟着值在圆括号中。

val greetStrings = new Array[String](3)  


greetStrings(0) = "Hello"  


greetStrings(1) = ", "  


greetStrings(2) = "world!\n"  



for (i - 0 to 2)  



 print(greetStrings(i))  

代码 3.1 用类型参数化数组

注意

尽管代码3.1里的代码演示了一些重要的概念,但它没有展示Scala里创建和初始化数组的推荐方式。你会在代码3.2中看到更好的方式。

如果想用一种更显式的方式,你可以显式定义greetStrings的类型:

val greetStrings: Array[String] = new Array[String](3)  

由于Scala有类型推断,这行代码与代码3.1里的第一行代码语义一致。不过这种形式说明了类型参数化部分(方括号里的类型名)形成了实例类型的部分,而值参数化部分(圆括号里的值)不是。greetStrings的类型是Array[String],不是Array[String](3)。

代码3.1的下三行代码初始化了greetStrings数组的每个元素:

greetStrings(0) = "Hello"  


greetStrings(1) = ", "  


greetStrings(2) = "world!\n"  

正如前面提到的,Scala里的数组是通过把索引放在圆括号里面访问的,而不是像Java那样放在方括号里。所以数组的第零个元素是greetStrings(0),不是greetStrings[0]。

这三行代码演示了搞明白Scala如何看待val的意义的重要概念。当你用val定义一个变量,那么这个变量就不能重新赋值,但它指向的对象却仍可以暗自改变。所以在本例中,你不能把greetStrings重新赋值成不同的数组;greetStrings将永远指向那个它被初始化时候指向的同一个Array[String]实例。但是你能一遍遍修改那个Array[String]的元素,因此数组本身是可变的。

代码3.1的最后两行包含一个for表达式用来依次输出每个greetStrings数组元素。

for (i - 0 to 2)  


 print(greetStrings(i))  

这个for表达式的第一行代码演示了Scala的另一个通用规则:如果方法仅带一个参数,你可以不带点或括号的调用它。本例中的to实际上是带一个Int参数的方法。代码0 to 2被转换成方法调用(0).to(2)。 请注意这个语法仅在你显示指定方法调用的接受者时才起作用。不可以写 pringln 10,但是可以写成“Console println 10”。

从技术上讲,Scala没有操作符重载,因为它根本没有传统意义上的操作符。取而代之的是,诸如+,-,*和/这样的字符可以用来做方法名。因此,当第一步里你在Scala解释器里输入1 + 2,你实际上正在Int对象1上调用一个名为+的方法,并把2当作参数传给它。如图3.1所示,你也可以使用传统的方法调用语法把1 + 2替代写成(1).+(2)。

Scala编程实例:带类型的参数化数组

这里演示的另一重要思想可以让你看到为什么数组在Scala里是用括号访问的。与Java比Scala很少有特例。数组和Scala里其他的类一样只是类的实现。当你在一个或多个值或变量外使用括号时,Scala会把它转换成对名为apply的方法调用。于是greetStrings(i)转换成greetStrings.apply(i)。所以Scala里访问数组的元素也只不过是跟其它的一样的方法调用。这个原则不仅仅局限于数组:任何对某些在括号中的参数的对象的应用将都被转换为对apply方法的调用。当然前提是这个类型实际定义过apply方法。所以这不是一个特例,而是一个通则。

与之相似的是,当对带有括号并包括一到若干参数的变量赋值时,编译器将把它转化为对带有括号里参数和等号右边的对象的update方法的调用。

例如,

greetStrings(0) = "Hello"  

将被转化为

greetStrings.update(0, "Hello")  

因此,下列Scala代码与你在代码3.1里的代码语义一致:

val greetStrings = new Array[String](3)  


greetStrings.update(0, "Hello")  


greetStrings.update(1, ", ")  


greetStrings.update(2, "world!\n")  



for (i - 0.to(2))  



  print(greetStrings.apply(i))  

Scala在对待任何事上追求概念的简洁性,从数组到表达式,包括带有方法的对象。你不必记住太多特例,如Java里原始类型和相应的包装类间的,或者数组和正常的对象间的差别。而且这种统一并未损害重要的性能代价。Scala编译器使用Java数组,原始类型,及可存在于编译完成代码里的原生数学类型。

尽管目前为止在这一步里你看到的例子编译运行良好,Scala提供了通常可以用在你真实代码里的更简洁的方法创造和初始化数组。它看起来就像展示在代码3.2中的样子。这行代码创建了长度为3的新数组,用传入的字串"zero","one"和"two"初始化。编译器推断数组的类型是Array[String] ,因为你把字串传给它。

val numNames = Array("zero", "one", "two") 

代码 3.2 创造和初始化数组

你在代码3.2里实际做的就是调用了一个叫做apply的工厂方法,从而创造并返回了新的数组。apply方法带可变数量个参数 ,被定义在Array的伴生对象:companion object上。你会在4.3节里学到更多关于伴生对象的东西。如果你是一个Java程序员,你可以认为这个就像在Array类上调用一个叫做apply的静态方法。更罗嗦的调用同样的apply方法的办法是:

val numNames2 = Array.apply("zero", "one", "two")    

相关推荐