变量
获取变量的值是一个耗时的工作时,可以考虑使用lazy var.
lazy val forLater = someTimeConsumingOperation()
scala> val first :: rest = List(1, 2, 3)
first: Int = 1
rest: List[Int] = List(2, 3)
函数定义
“=”并不只是用来分割函数签名和函数体的,它的另一个作用是告诉编译器是否对函数的返回值进行类型推断!如果省去=,则认为函数是没有返回值的!
比如:
scala> def myFirstMethod() = { “exciting times ahead” }
myFirstMethod: ()java.lang.String
scala> def myFirstMethod(){ “exciting times ahead” }
myFirstMethod: ()Unit
函数字面量:FUNCTION LITERALS
In Scala you can also pass a function as a parameter to another function, and most of the time in those cases I provide an inline definition of the function. This passing of functions as a parameter is sometimes loosely called closure (passing a function isn’t always necessarily closure; you’ll look into that in chapter 4). Scala provides a shorthand way to create a function in which you write only the function body, called function literals.
简单地说就是: 函数字面量就是省去了函数签名(主要就是函数名和参数声明)只留下函数体的一段代码!注意,这个还不同于匿名函数,匿名函数只是没有函数名,但是参数声明是不会省略的!对于函数字面量来讲,因为省略了参数声明,当函数体内需要使用到参数时,就会使用一个下划线来指代!这也可以说是函数字面量的一个特征了!
例如:
//很显然,花括号中的部分是一个匿名函数
scala> evenNumbers.foldLeft(0) { (a: Int, b:Int) => a + b }
//花括号中的部分依然是匿名函数,只是省去了参数的类型声明
scala> evenNumbers.foldLeft(0) { (a, b) => a + b }
//演化到这个版本时,发生了一些实质性的变化:
//参数声明也被省略了,很显然,我们再也不能将其称之为匿名函数了!
//随着参数声明的取消,带来了一个问题:如何在函数体内指代和标示参数呢?
scala> evenNumbers.foldLeft(0) { _ + _ }
在scala里, 一个下划线代表一个参数!
闭包:Closure
A closure is any function that closes over the environment in which it’s defined. For example, closure will keep track of any variable changes outside the function that are being referred to inside the function.
def breakable(op: => Unit) { … }
What’s this op: => Unit? The special right arrow (=>) lets Scala know that the breakable function expects a function as a parameter. The right side of the => defines the return type of the function—in this case it’s Unit (similar to Java void)—and op is the name of the parameter. Because you haven’t specified anything on the left side of the arrow, it means that the function you’re expecting as a parameter doesn’t take any parameter for itself.
如果我们需要的传入参数是一个代参数且有返回值的函数呢? 这样的函数作参数应该如何描述呢?
def foldLeft(initialValue: Int, operator: (Int, Int) => Int)= { … }
让我们这样来理解吧:既然对于函数式编程语言来说,函数是第一位(first class)的,它可以像其他数据类型一样被使用,那么当它作为函数的参数时,我们需要约定一个语法来描述这个”参数”(实际上是一个函数)的”类型”(实际上应该是这个函数的”元信息“),那么对于一个函数来说,它的”类型“应该怎样去描述呢?从语言的设计者角度来考虑的话,那当然最合理的描述方式是:陈述出这个函数的参数类型和它的返回值类型!这也正是operator: (Int, Int) => Int)所做的!简单明了,合情合理!
数组
scala> val array = new Array[String](3)
array: Array[String] = Array(null, null, null)
scala> array(0) = "This"
scala> array(1) = "is"
scala> array(2) = "mutable"
对于给数组赋值的语句:array(0) = “This”,这里要说明的是:不同于java中的array[0] = “This” 在scala中,[]永远是用来制定参数类型的!
FOR循环
val files = new java.io.File(".").listFiles
for(file <- files) {
val filename = file.getName
if(fileName.endsWith(".scala")) println(file)
}
The only thing that looks different from for loops in Java or C# is the expression file <- files. In Scala this is called a generator, and the job of a generator is to iterate through a collection.
scala> val aList = List(1, 2, 3)
aList: List[Int] = List(1, 2, 3)
scala> val bList = List(4, 5, 6)
bList: List[Int] = List(4, 5, 6)
scala> for { a <- aList; b <- bList } println(a + b)
5
6
7
6
7
8
7
8
9
scala> val result = for { a <- aList; b <- bList } yield a + b
result: List[Int] = List(5, 6, 7, 6, 7, 8, 7, 8, 9)
scala> for(r <- result) println(r)
5
6
7
6
7
8
7
8
9
注:for语句的花括号{}并不是必须的,你完全可以使用().
模式匹配:Pattern Matching
模式匹配,示例一:
ordinal(args(0).toInt)
def ordinal(number:Int) = number match {
case 1 => println("1st")
case 2 => println("2nd")
case 3 => println("3rd")
case 4 => println("4th")
case 5 => println("5th")
case 6 => println("6th")
case 7 => println("7th")
case 8 => println("8th")
case 9 => println("9th")
case 10 => println("10th")
case _ => println("Cannot do beyond 10")
}
case _ to match everything else.
模式匹配,示例二:
在下面的这个例子中展示了scala一些内置的预定义的Pattern,专门应用于case上的,例如下面例子中的:f,s, rest
scala> List(1, 2, 3, 4) match {
case f :: s :: rest => List(f, s)
case _ => Nil
}
res7: List[Int] = List(1, 2)
模式匹配,示例三:
val suffixes = List("th", "st", "nd", "rd", "th", "th", "th","th", "th","th");
println(ordinal(args(0).toInt))
def ordinal(number:Int) = number match {
case tenTo20 if 10 to 20 contains tenTo20 => number + "th"
case rest => rest + suffixes(number % 10)
}
类:Class
What val and var do is define a field and a getter for that field, and in the case of var an additional setter method is also created. When both of them are missing, they’re treated as private instance values, not accessible to anyone outside the class.
对于Class的field的修饰符有如下约定:
- 使用var声明field,则该field将同时拥有getter和setter
scala> class MongoClient(var host:String, var port:Int)
- 使用val声明field,则该field只有getter。这意味着在初始化之后,你将无法再修改它的值。
scala> class MongoClient(val host:String, val port:Int)
- 如果没有任何修饰符,则该field是完全私有的。
scala> class MongoClient(host:String, port:Int)