第03章scala入门续
第7步 用类型参数化数组
数组是内容是可变的
当你用scala实例化对象时,可以用值和类型来对其参数化
用值来参数化
var big = new BigInteger("12345")
用类型来参数化,用方括号括起来类型
var greetStrings = new Array[String](3);
//greetStrings.update(0, "Hello")
greetStrings(0) = "Hello"
greetStrings(1) = ","
greetStrings(2) = "world! \n"
//0 to 2返回的不是数组,而是另一种序列
for (i <- 0 to 2) {
//greetStrings.apply(0)
println(greetStrings(i))
}
- scala数组访问方式是将下标放在圆括号里面
- 如果一个方法只接收一个参数,当调用它时,可以不用句号和圆括号。本例中 0 to 2 会转换成 0.to(2)方法调用,这种方式仅在显示的给出方法调用的目标对象时才有效。不能写成println 10,单可以 Console println 10
- scala从技术上并没有操作符重载,类似+、-、*、/这样的字符可以被用做方法名。1 + 2 实际上是调用 Int 对象 1上名为 + 的方法,将 2作为参数传入,即 1.+(2)
- 当你用一组圆括号将一个或多个值括起来,将其应用(apply)到某个对象时。scala会将字段代码转换成对这个对象的apply的方法调用。
greetStrings(i)
//会转换成
greetStrings.apply(i)
- 通过圆括号应用了一个或多个参数的变量进行赋值时,scala会将代码转换成update的方法调用。
greetStrings(0) = "Hello"
//会转换成
greetStrings.update(0, "Hello")
更精简方式创建数组
var numNames = Array("zero", "one", "two")
//转换成 Array.apply("zero", "one", "two") 方法调用
第 8 步 使用列表
List是不可变的
函数式编程的重要理念之一是方法不能有副作用,一个方法唯一要做的是计算并返回一个值
var oneTwo = List(1, 2)
//转换成 List.apply(1,2) 方法调用
var threeFour = List(3, 4)
var oneTwoThreeFour = oneTwo ::: threeFour
var twoThree = List(2,3)
var oneTwoThree = 1 :: twoThree
- List有个叫 ::: 方法,用与将列表拼接
- 1 :: twoThree 中, :: 是右操作元 twoThree 的方法,如果方法名的最后一个字符是冒号,该方法的调用会发生在它的右操作元上
- Nil为空列表
- 列表在列头添加元素,:+方法往末尾添加元素,ListBuffer是可变列表,支持追加操作,完成调用toList即可
第 9 步 使用元组
元组也是不可变的
var pair = (99, "L")
println(pair._1)
println(pair._2)
多个对象放在括号里,用逗号隔开
访问时用句点、下划线和从1开始的下标来访问每个元素
第 10 步 使用集合映射
数组是可变的,列表与元组是不可变的。scala同时还提供了集(set)和映射(map)的可变的和不可变的不同选择
scala提供了3个特质都叫Set,不过它们的完成名称不相同
//jetSet为不可变集
var jetSet = Set("Boeing", "Airbus")
// jetSet += "Leat" 为 jetSet = jetSet + "Leat" 的简写。因此jetSet不能用val修饰
jetSet += "Leat"
import scala.collection.mutable
val movieSet = mutable.Set("Hitch", "Poltergeist");
//+=为方法,movieSet可以用val定义,非重新赋值
movieSet += "Shrek"
- 默认是创建不可变集,想用可变集,需要导入
- 可变集提供了 +=方法
- 不可变集使用+=是重新赋值,因此必须用var定义
var treasureMap = mutable.Map[Int, String]()
treasureMap += (1 -> "Go to island.")
treasureMap += (2 -> "find big X on ground.")
println(treasureMap(1))
Map必须显示声明参数类型
scala允许任何对象调用 ->方法(隐式转换)
第 11 步 认识函数式编程风格
函数式编程与指令式编程风格显著区别是如果代码包含任何var变量,它通常是指令式风格的,如果代码没有var,那么它可能是函数式的。scala鼓励你更倾向于使用val,倾向于使用无副作用的函数,这样的好处之一是让你的程序更容易测试。
第 12 步 从文件读取文本行
object HelloWorld {
def main(args: Array[String]) = {
import scala.io.Source
if (args.length > 0) {
var lines: List[String] = Source.fromFile(args(0)).getLines().toList
var maxLengthLine = lines.reduceLeft((a, b) => {
if (a.length > b.length) a else b
})
var maxLength = widthOfLine(maxLengthLine);
for (line <- lines) {
var numSpaces = maxLength - widthOfLine(line);
var padding = " " * numSpaces;
println(padding + line.length + " | " + line)
}
} else {
Console.err.println("Please enter filename")
}
}
def widthOfLine(line: String): Int = {
line.length.toString.length
}
}
- Source.fromFile(args(0))尝试打开指定的文件并返回Source对象,getLines返回一个Iterator[String],Iterator一旦遍历完成,迭代器就会消失,通过toList转换成列表。
- 代码无需开启关闭IO流
- reduceLeft方法将传入的函数应用到lines的头两个元素,然后继续讲这个传入的函数应用到前一步得到的值和lines中的下一个元素,直至遍历完整个列表