Scala = Scalable Language
纯面向对象、函数式编程、静态类型、扩展性(以库的形式无缝对接其它语言)、并发性。
Scala 源代码被编译成 Java 字节码,运行于 JVM 之上,可以调用现有的 Java 类库。
// hello.scala
object HelloWorld { // 对象
// (参数:类型):返回值类型
def main(args: Array[String]): Unit = { // 入口必须是 main
println("Hello, world!")
}
}
直接运行:
$ scala hello.scala
Hello, world!
也可以先编译再运行:
$ scalac hello.scala # 生成 HelloWorld.class, HelloWorld$.class
$ scala HelloWorld # 类名
Hello, world!
scala 跟 python 一样,也是个交互式的 Shell。
区分大小写
类名首字母大写,每个单词的首字母大写:class MyFirstScalaClass
方法名首字母小写: def myMethodName
文件名与 object 名称一致
入口:def main(args: Array[String])
注释://
或 /* ... */
语句结尾的 ;
可选
// 可以放在任何地方
import java.awt.Color
import java.awt._ // 引入包内所有成员
import java.awt.{Color, Font}
import java.util.{HashMap => JavaHashMap} // 重命名
import java.util.{HashMap => _, _} // 引入所有成员,但 HashMap 被隐藏
Byte,Short,Int,Long
Float,Double
Char,String
Boolean
Unit // 类似 void,表示无返回值
Null
Nothing // 它是任何其他类型的子类型
Any // 是所有其它类的超类
Anyref // 所有引用类的基类
字符 & 字符串:
'c' // char
"string"
"""string""" // 可分行
// 名 : 类型
var myVar : String = "Foo" // 变量。必须给初始值。
val myVal : String = "Foo" // 常量
var myVar = 10; // 自动判断类型
val myVal = "Hello, Scala!";
val xmax, ymax = 100
val pa = (40,"Foo") // 元组用 val
public
private // 仅类或对象的内部可见
protected // 仅子类可见
private[x] // private,但对 x 可见
protected[x]
for( var x <- Range ) // "<-" 表示赋值
for( a <- 1 to 10) // 包含 10
for( a <- 1 until 10) // 不含 10
for( a <- 1 to 3; b <- 1 to 3)
for( var x <- List )
for( a <- List(1,2,3,4,5,6) )
// 条件过滤
for( a <- List
if a != 3; if a < 8 )
// yield
var retVal = for{ var a <- List
if a != 3; if a < 8
}yield a
for( a <- retVal){
println( "Value of a: " + a );
}
def functionName ([参数列表]) : [return type]
def addInt( a:Int, b:Int ) : Int = {...}
def printMe( ) : Unit = {...} // 无返回值
def printStrings( args:String* ) = {...} // 可变长参数
def addInt( a:Int=5, b:Int=7 ) : Int = {...} // 默认参数
传值调用(call-by-value):先计算参数表达式的值,再应用到函数内部。
传名调用(call-by-name):将未计算的参数表达式直接应用到函数内部。
区别就在于事先计算表达式还是到被调用的地方才计算。
def time() = { System.nanoTime }
def delayed( t: => Long ) = {...} // "=>" 表示传名,t 是表达式,Long 是结果类型
delayed(time());
偏应用函数:
def log(date: Date, message: String) = {...}
val logWithDateBound = log(date, _ : String) // 第一个绑定,用下划线替代缺失的参数列表
logWithDateBound("msg")
指定函数参数名:
def printInt( a:Int, b:Int ) = {...}
printInt(b=5, a=7)
函数式编程(参数和返回结果可以是函数):
def apply(f: Int => String, v: Int) = f(v)
def layout[A](x: A) = "[" + x.toString() + "]" // 泛型
println( apply( layout, 10) )
匿名函数:
var inc = (x:Int) => x+1
var mul = (x: Int, y: Int) => x*y
柯里化(Currying):
def add(x:Int,y:Int) = x+y // add(1,2)。普通函数
def add(x:Int)(y:Int) = x+y // add(1)(2)。柯里化。其实调用了两次普通函数
def add(x:Int)=(y:Int)=>x+y // 效果同上
闭包:
object Test {
//...
var factor = 3
val multiplier = (i:Int) => i * factor
}
buf += 'a' // 连接字符
buf ++= "bcdef" // 连接字符串
var len = buf.length()
println("msg")
str1.concat(str2) // 连接
var str = "str1" + "str2"
var fs = printf("format: " + "%f %d %s", floatVar, intVar, stringVar) // 返回值而不是输出
var z:Array[String] = new Array[String](3)
var z = new Array[String](3)
var z = Array("Runoob", "Baidu", "Google")
z(0) = "Runoob"; z(1) = "Baidu"; z(4/2) = "Google"
var myList = Array(1.9, 2.9, 3.4, 3.5)
for ( x <- myList ) {...} // 遍历元素
for ( i <- 0 to (myList.length - 1)) {...} // 遍历索引
var myMatrix = ofDim[Int](3,3) // 多维数组。函数 ofDim[T]() 创建定长数组。
myMatrix(i)(j) = j
var myList3 = concat(myList1, myList2) // 合并数组
var myList = range(10, 20, 2) // (strat,end,step)
Collection 类型:List、Set、Map、Tuple、Option(类似枚举)、Iterator。
val x = List(1,2,3,4)
var x = Set(1,3,5,7)
val x = Map("one" -> 1, "two" -> 2, "three" -> 3)
val x = (10, "Runoob") // 元组
val x:Option[Int] = Some(5)
val empty: List[Nothing] = List() // 空列表
val empty = Nil // 空列表
val dim: List[List[Int]] = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1)) // 二维列表
val site = "Runoob" :: ("Google" :: ("Baidu" :: Nil)) // List(Runoob, Google, Baidu)
val nums = 1 :: (2 :: (3 :: (4 :: Nil))) // List(1, 2, 3, 4)
val dim = (1 :: (0 :: (0 :: Nil))) ::
(0 :: (1 :: (0 :: Nil))) ::
(0 :: (0 :: (1 :: Nil))) :: Nil
list.head // 首元素
list.tail // 尾元素
list.isEmpty
list.reverse
List.concat(list1, list2) // 连接
var list = list1 ::: list2 // 连接
var list = list1.:::(list2) // 连接
val num = List.fill(10)(2) // 填充 10 个 2
List.tabulate(4)(n => n * n) // List(0, 1, 4, 9)
List.tabulate(3,4)(_*_) // List(List(0, 0, 0, 0), List(0, 1, 2, 3), List(0, 2, 4, 6))
var x = List(1) // List(1)
var y = 2 +: x // List(2, 1)
var y = x :+ 3 // List(1, 3)
list.exists(s => s == "Hah")
list.filter(s => s.length == 3)
val it = Iterator("Baidu", "Google", "Runoob", "Taobao")
while (it.hasNext) {...}
it.max
it.min
it.size // 调用后 size 变 0
it.length // 同 size
定义类 & 实例化:
class Foo (x:Int, y:Int) {}
val foo = new Foo(10, 20)
继承:
// override val x 表示重写父类的字段
// 只能继承一个父类
class Bar (override val x:Int, override val y:Int, val z:Int) extends Foo(x,y) {}
重写非抽象方法:
class Person {
var name = ""
// override 表示非抽象方法
override def toString = getClass.getName + "[name=" + name + "]"
}
class Employee extends Person {
var salary = 0.0
// override 表示重写非抽象方法
override def toString = super.toString + "[salary=" + salary + "]"
}
单例模式:
// 用 object 就是单例
object Test {}
类似 Java 中的抽象类,特征可以多重继承。
trait Equal {
def isEqual(x: Any): Boolean
def isNotEqual(x: Any): Boolean = !isEqual(x)
}
class Point(xc: Int, yc: Int) extends Equal {
def isEqual(obj: Any) = ...
}
def matchTest(x: Any): Any = x match {
case 1 => "one"
case "two" => 2
case y: Int => "scala.Int"
case _ => "many" // _ 相当于 default
}
样例类:
object Test {
def main(args: Array[String]) {
//...
for (person <- List(alice, bob, charlie)) {
person match {
case Person("Alice", 25) => println("Hi Alice!")
case Person("Bob", 32) => println("Hi Bob!")
case Person(name, age) => println("Age:" +age+ "year, name:" +name+ "?")
}
}
}
// 样例类
case class Person(name: String, age: Int)
}
val pattern = "Scala".r // 用 str.r() 构造 Regex 对象
val str = "Scala is Scalable and cool"
println(pattern findFirstIn str) // 找到首个匹配项。findAllIn
val pattern = new Regex("(S|s)cala")
val pattern = "(S|s)cala".r
println((pattern findAllIn str).mkString(",")) // 用逗号连接返回结果
println(pattern replaceFirstIn(str, "Java")) // 替换第一个匹配项。replaceAllIn
抛出异常:
throw new IllegalArgumentException
异常处理:
import java.io.FileNotFoundException
import java.io.IOException
try {
//...
} catch {
case ex: FileNotFoundException => {...}
case ex: IOException => {...}
} finally {
//...
}
// 写文件
import java.io._
val writer = new PrintWriter(new File("test.txt" ))
writer.write("hello")
writer.close()
// 读文件
import scala.io.Source
Source.fromFile("test.txt" ).foreach{
print
}
// 读终端
print("Input: " )
val line = Console.readLine
Class 是抽象的,不占内存,可以带参数。
Object 是(类的)实体,占用内存,不能带参数。
用 Object 就表示单例模式。
当一个 Object 和 Class 同名时(当然必须在同一个文件),称它们是伴生的(companion),分别叫做伴生对象和伴生类。
// 伴生类
class Marker private(val color:String) {...}
// 伴生对象
object Marker{
// 可以访问伴生类的私有属性和方法
def main(args: Array[String]) {...}
}
一个类最多只能继承一个父类,但是可以继承多个特征,都用 extends 关键字。
是一种特殊的类,经过优化以用于模式匹配。
当实例化对象时,会自动调用类的 apply()
方法,比如传入 name 和 age 返回一个 Person 对象。那么自然还有一个对应的反函数 unapply()
,传入 Person 对象就返回当初创建它的参数,即 name 和 age。这个 unapply()
函数就叫提取器,能从对象中提取出创建它的参数。