Parameterize Arrays
簡要的語法範例
scala> val arrayDemo: Array[Int] = new Array(5)
arrayDemo: Array[Int] = Array(0, 0, 0, 0, 0)
scala> arrayDemo
res2: Array[Int] = Array(0, 0, 0, 0, 0)
Array表示符 ( )
So
the first element in a Scala array named
steps
is
steps(0)
, not
steps[0]
.
For Java Developer
相同處
- 實例化同樣使用 new 關鍵字
- 相同類型的元素值可變序列, Array是一個元素值可變的物件
- 實例化後長度不可變
不同處
- 宣告 Array 不加 [ ]
- 實例化 Array 語句為 new Array[Type](length)
- 存取 Array 索引使用 (index)
- Scala 的 Array 優於 Java 可使用泛型化參數與類型變數
- Array[String](10)
- Array[T](10)
- Scala陣列是一個所有object都共享相同類型的可變序列。
Examples
Scala 的快速排序,
http://www.qqread.com/java/2009/08/f472573.html
Parameterize Array
s with types
In addition to being functional, Scala is object-oriented. In Scala, as in Java, you define
a blueprint for objects with classes. From a class blueprint, you can instantiate
objects, or class instances, by using new
. For example, the following Scala code instantiates a new String
and prints it out:
val s = new String("Hello, world!")
println(s)
In the previous example, you parameterize the String
instance with the initial value "Hello, world!"
.
You can think of parameterization as meaning configuring an instance at the point in your program that you
create that instance. You configure an instance with values by passing objects to a constructor of the
instance in parentheses, just like you do when you create an instance in Java. If you place the previous code
in a new file named paramwithvalues.scala
and run it with scala paramswithvalues.scala
, you'll see the familiar
Hello, world!
greeting printed out.
In addition to parameterizing instances with values at the point of instantiation, you can in Scala
also parameterize them with types. This kind of parameterization is akin to specifying a type in
angle brackets when instantiating a generic type in Java 5 and beyond. The main difference is that
instead of the angle brackets used for this purpose in Java, in Scala you use square brackets. Here's an example:
val greetStrings = new Array[String](3)
greetStrings(0) = "Hello"
greetStrings(1) = ", "
greetStrings(2) = "world!\n"
for (i <- 0 to 2)
print(greetStrings(i))
In this example, greetStrings
is a value of type Array[String]
(say this as, “an array of string”)
that is initialized to length 3 by passing the value 3
to a constructor in parentheses in the first line of code.
Type this code into a new file called paramwithtypes.scala
and execute it with scala paramwithtypes.scala
,
and you'll see yet another Hello, world!
greeting.
Note that when you parameterize an instance with both a type and a value, the type comes first in its
square brackets, followed by the value in parentheses.
Had you been in a more explicit mood, you could have
specified the type of greetStrings
explicitly like this:
val greetStrings: Array[String] = new Array[String](3)
// ...
Given Scala's type inference, this line of code is semantically equivalent to the actual first line of
code in paramwithtypes.scala
.
But this form demonstrates that while the type parameterization portion (the type names in square brackets) form
part of the type of the instance, the value parameterization part (the values in parentheses) do not.
The type of greetStrings
is Array[String]
, not Array[String](3)
.
The next three lines of code in paramwithtypes.scala
initializes each element of the greetStrings
array:
// ...
greetStrings(0) = "Hello"
greetStrings(1) = ", "
greetStrings(2) = "world!\n"
// ...
As mentioned previously, arrays in Scala are accessed by placing the index inside parentheses, not square brackets
as in Java. Thus the zeroeth element of the array is greetStrings(0)
, not greetStrings[0]
as in Java.
These three lines of code illustrate an important concept to understand about Scala concerning the meaning of val
. When
you define a variable with val
, the variable can't be reassigned, but the object to which it refers could potentially still be
mutated. So in this case, you couldn't reassign greetStrings
to a different array; greetStrings
will always
point to the same Array[String]
instance with which it was initialized. But you can change the elements
of that Array[String]
over time, so the array itself is mutable.
The final two lines in paramwithtypes.scala
contain a for comprehension that prints out each greetStrings
array element in turn.
// ...
for (i <- 0 to 2)
print(greetStrings(i))
The first line of code in this for comprehension illustrates another
general rule of Scala: if a method takes only one parameter, you can
call it without a dot or parentheses. to
is actually a method that takes one Int
argument.
The code 0 to 2
is transformed into the method call 0.to(2)
.
(This to
method actually returns not an Array
but a Scala iterator that returns the
values 0, 1, and 2.)
Scala doesn't technically have operator overloading, because it doesn't actually have operators
in the traditional sense. Characters such as +
, -
, *
, and /
, have no special meaning in Scala, but they can
be used in method names. Thus, the expression 1 + 2
, which was the first Scala code you typed into the interpreter
in Step 1, is essential in meaning to 1.+(2)
, where +
is the name of a method defined in class scala.Int
.
Another important idea illustrated by this example will give you insight into why arrays are accessed with parentheses
in Scala. Scala has fewer special cases than Java. Arrays are simply instances of classes like any other class in
Scala. When you apply parentheses to a variable and pass in some arguments, Scala will transform that into an invocation of
a method named apply
. So greetStrings(i)
gets transformed into greetStrings.apply(i)
. Thus accessing the
element of an array in Scala is simply a method call like any other method call.
What's more, the compiler will transform
any application of parentheses with some arguments on any type into an apply method call, not just arrays. Of
course it will compile only if that type actually defines an apply
method.
So it's not a special case; it's a general rule.
Similarly, when an assignment is made to a variable that is followed by
some arguments in parentheses, the compiler will transform
that into an invocation of an update
method that takes two
parameters. For example,
greetStrings(0) = "Hello"
will essentially be transformed into
greetStrings.update(0, "Hello")
Thus, the following Scala code is semantically equivalent to the code
you typed into paramwithtypes.scala
:
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 achieves a conceptual simplicity by treating everything, from arrays to expressions, as objects with
methods. You as the programmer don't have to remember lots of special cases, such as the differences in
Java between primitive and their corresponding wrapper types, or between arrays and regular objects. However, it
is significant to note that in Scala this uniformity does not usually come with a performance cost as it
often has in other languages that have aimed to be pure in their object orientation. The Scala compiler uses
Java arrays, primitive types, and native arithmetic where possible in the compiled code. Thus Scala really does
give you the best of both worlds in this sense: the conceptual simplicity of a pure object-oriented language
with the runtime performance characteristics of language that has special cases for performance reasons.