第一章 基础
操作符
1.+(2) 和 1 + 2 的效果一样, +是int类型的一个方法, 你可以重载它, 然后用着两种语法调用
导入
import scala.math._ 是导入math包中的所有方法
方法调用
"hello".distinct 通常来说, 不带参数切不改变原来对应的方法不带括号
apply
"hello"(4) 是 "hello".apply(4)的简写, 可以理解为实现了apply方法. 就可以直接重载()
第二章 控制结构和函数
条件表达式
var s = if (2 > 1) 1 else 0 # 条件表达式会返回值
var s = -1; if (2 > 1) s = 1 else s = 0 # 也可以在表达式内部赋值
var s = if (2 < 1) 1 # 得到的值是 AnyVal = (), 缺失else语句会自动补全为 else ()
块表达式
val distance = {
val dx = 1
val dy = 2
dx + dy
}
块中最后一个表达式的值就是块的值
循环
while (n > 0) {
n -= 1
}
for (i <- 1 to 10) {
print(i)
}
for (i <- 1 until 10) {
print(i)
}
for (i <- "hello") {
print(i)
}
scala并没有break和continue, 如果想退出循环, 可以有以下选择
1. 使用Boolean类型的控制变量
2. 将循环写在嵌套函数中, 必要时return
3. 使用Breaks中的break方法, 不过这个方法是通过捕获异常完成的, 效率较低
import scala.util.control.Breaks.break
for (i <- 1 to 10){
println(i)
break
}
高级for循环
for (i <- 1 to 3; j <- 1 to 3) {
println(i, j)
}
for (i <- 1 to 3; j <- 1 to 3 if i != j) {
println(i, j)
}
for (i <- 1 to 3; from = 4 - i; j <- from to 3) {
println(i, j)
}
for推导式
for (i <- 1 to 7) yield {
1 % 3
}
for (c <- "hello"; i <- 0 to 1) yield (c + i).toChar
for (i <- 0 to 1; c <- "hello") yield (c + i).toChar
函数
def abs(x: double) = {
var r = 1
r + 1
}
def default_p(str: String = "abc") = {
str
}
变长参数
def sum(args: Int*) = {
"sum"
}
如果传入的参数是序列, 要用如下的方式调用
val s = sum(1 to 5: _*)
指定返回值类型(Int)的函数
def abs:Int = 5
没有参数且不指定返回值类型的函数
def abs2 = 6
过程
过程不返回值, 只是为了得到过程中的某些效果, 比如打印
def box(s: String) {
println("aaa")
}
懒值
当声明为懒值时, 初始化将被推迟, 直到首次对它取值, 常用在开销较大的打开文件等操作
lazy val s = "ss"
异常
if (x > 0) {
sqrt(x)
} else {
throw new IllegalArgumentException("abc")
}
try {
"abc".toInt
} catch {
case error: NumberFormatException => print("qwe")
}
try {
"abc".toInt
} finally {
print("qwe")
}
数组
定长数组
val nums = new Array[Int](10)
val s = Array("hello", "world")
s(0) = "googbye"
变长数组
import scala.collection.mutable.ArrayBuffer
val b = ArrayBuffer[Int]()
b += 1
b += (1, 2, 3, 4)
b ++= Array(8, 13, 21)
b.trimEnd(5)
b.insert(2, 6)
b.insert(2, 7, 8, 9)
b.remove(2)
b.remove(2, 3)
b.toArray
数组遍历
val s = Array("hello", "world")
for (i <- 0 until s.length) {
println(i, s(i))
}
for (i <- 0 until (s.length, 2)) {
println(i, s(i))
}
for (i <- (0 until s.length).reverse) {
println(i, s(i))
}
for (elem <- s) {
println(elem)
}
数组转换
数组转换会生成新的数组, 类型和原来的数组类型一致(数组或变长数组)
val a = Array(1, 2, 3, 4, 5, 6)
for (elem <- a if elem % 2 == 0) yield {
2 * elem
}
常用算法
Array(1, 2, 3).sum
Array(1, 2, 3).max
Array(1, 2, 3).min
val a = Array(1, 4, 2, 6)
val bSorted = b.sorted(_ < _)
import scala.util.Sorting.quickSort
quickSort(a)
a.mkString(" and ")
a.mkString("<", " and ", ">")
多维数组
val triangle = new Array[Array[Int]] (10)
for (i <- 0 until triangle.length){
triangle(i) = new Array[Int] (5)
}
val matrix = Array.ofDim[Int] (3, 4)
映射
构造映射
val scores = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
val scores = scala.collection.mutable.Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
val scores = new scala.collection.mutable.HashMap[String, Int]
获取映射中的值
scores("Alice")
scores.contains("Alice")
scores.getOrElse("Alice", 0)
更新映射中的值
scores("ss") = 5
scores += ("Bob" -> 3, "Cindy" -> 8)
scores -= "Bob"
对于不可变的映射, 可以做如下操作, 使其返回一个新的映射, 效率不是很低, 他们共享大部分数据结构
val newScores = scores + ("Bob" -> 3, "Cindy" -> 8)
scores = scores + ("Bob" -> 3, "Cindy" -> 8)
scores = scores - "Bob"
迭代映射
for ((k, v) <- scores) {
println(k, v)
}
for (k <- scores.keySet) {
println(k)
}
for (k <- scores.values) {
println(k)
}
for ((k, v) <- scores) yield {
(v, k)
}
已排序映射
val scores = scala.collection.immutable.SortedMap("Cindy" -> 8)
val scores = scala.collection.mutable.LinkedHashMap("Cindy" -> 8)
元组
元组是不同类型的值的集合, 可以用在函数需要返回不止一个值得时候
val t = (1, 3.14, "abc")
val second = t._2
val (first, second, third) = t
对偶数组
val symbols = Array("<", "-", ">")
val counts = Array(2, 10, 2)
val paris = symbols.zip(counts)
for ((s, n) <- paris) {
println(s, n)
}
类
简单类和无参方法
class Counter {
private var value = 0
def increment() {
value += 1
}
def current() = {
value
}
}
val myCounter = new Counter
myCounter.increment()
println(myCounter.current)
带getter和setter属性
scala对每个字段都提供getter和setter方法
class Person {
var age = 0
}
val fred = new Person
fred.age
fred.age = 21
可以自己定义getter和setter方法
class Person {
private var privateAge = 0
def age = privateAge
def age_=(newValue: Int) {
if (newValue > privateAge) {
privateAge = newValue
}
}
}
val fred = new Person
fred.age
fred.age = 21
fred.age = 19
只有getter属性
class Person {
val age = 0
}
有时候我们需要这样一个属性, 客户端不能更改, 但是可以被类本身修改
class Person {
private var age = 0
def currentAge = age
}
对象私有字段
class Person {
private[this] var age = 0
}
Bean属性
scala.reflect.BeanProperty 可以使scala类生成符合java规范的getter和setter方法
辅助构造器
1. 辅助构造器名称为this
2. 每一个辅助构造器都必须以一个对先前已定义的辅助构造器或主构造器的调用开始
class Person {
private var name = ""
private var age = 0
def this(name: String) {
this()
this.name = name
}
def this(name: String, age: Int) {
this(name)
this.age = age
}
}
val p1 = new Person
val p2 = new Person("Tom")
val p3 = new Person("Tom", 12)
主构造器
class Person(val name: String, val age: Int = 0) {}
class Person(val name: String, val age: Int) {
println("abc")
}
针对主构造器参数生成的字段和方法
主构造器参数 生成的字段和方法
name: String 只有主构造器可以使用, 主构造器定义的变量才可以被对象访问
private val/var name: String 私有字段, 私有getter/setter
val/var name:String 私有字段, 公有getter/setter
@BeanProperty val/var name:String 私有字段, 公有java版getter/setter
class Person(name: String) {
val myname = name
}
val p = new Person("Tom")
p.name
p.myname
class Person(val name: String) {}
val p = new Person("Tom")
p.name
对象
单例对象
对象的构造器在对象第一次使用的时候被调用
对象不能提供构造器参数
可用来存放工具函数或常量, 高效的共享某个不可变实例
object Accounts {
private var lastNumber = 0
def newUniqueNumber() = {lastNumber += 1; lastNumber}
}
Accounts.newUniqueNumber()
伴生对象
类和它的伴生对象可以相互访问私有特性, 它们必须存在于同一个源文件中
object Accounts {
private var lastNumber = 0
def newUniqueNumber() = {lastNumber += 1; lastNumber}
}
class Accounts {
val id = Accounts.newUniqueNumber()
private var balance = 0.0
def deposit(amount: Double) {balance += amount}
}
var myAccount1 = new Accounts
myAccount1.id
var myAccount2 = new Accounts
myAccount2.id
扩展类或特质的对象
有点类似于继承...
一个有用的场景是给出可被共享的缺省对象
abstract class UndoableAction(val description: String) {
def undo(): Unit
def redo(): Unit
}
object DoNothingAction extends UndoableAction("Nothing") {
override def undo() {}
override def redo() {}
}
apply方法
当遇到如下形式的表达式时, apply方法会被调用
Object(parameter1, parameter2 ...)
通常, 这样一个apply方法返回的是伴生类的对象
比如Array对象的apply方法, 我们使用 Array("Mary", "Tom") 来创建一个数组, 而使用构造器创建(new Array(100))这种形式, 就会比较麻烦, 尤其是在创建多维数组的时候
注意: Array(100) 创建的是 [100] 这样一个数组, new Array(100) 创建的是包含100个null元素的数组
class Account private (val id: Int, initialBalance: Double) {
private var balance = initialBalance
}
object Account {
def apply(id: Int, initialBalance: Double) = new Account(id, initialBalance)
}
val acct = Account(10, 100.0)
应用程序对象
每个scala都必须从一个对象的main方法开始
object Hello {
def main(args: Array[String]) {
println("hello")
}
}
也可以通过App特质, 将程序代码放入一个构造器方法内
object Hello extends App {
if (args.length > 0) {
print("hello" + args(0))
} else {
println("hello")
}
}
枚举
再议, 再议....
包和引入
略