Scala学习笔记(2)

在Java和C++中,会区分表达式(3+4)和语句(statements)(if语句)。表达式有一个值,语句执行一个操作。Scala与其他语句最基本的不同,就是它的所有结构都有值。

2.1 条件表达式

Scala中if/else的语法与Java和C++中一致。但是,在Scala中,if/else有一个值,即跟在if或者else之后的表达式的值。

val s = if (x > 0) 1 else -1 //式①

这里if/else表达式的值是1或者-1,这个值可以直接赋值给ss可以是val。该语句的效果等价于:

if (x > 0) s = 1 else s = -1

这里s只能是var。

Scala中,每个表达式都有类型。在式①中,两个分支都是Int,所以表达式的类型也是Int。

if (x > 0) "positive" else -1

对于上面这个表达式,两个分支的类型不一致,则表达式的类型是两个分支的共同超类(common supertype),StringInt的共同超类是Any

if (x > 0) 1
if (x > 0) 1 else ()

省略了else的情况,相当于else ()。Scala中,每个表达式,都应该有某个值。Scala有一个Unit类,和Java还有C++中的void类似。Unit类有一个值,写作()()是“没有有用值(no useful value)”的占位符。void是没有值的,而Unit有一个表示“没有值(no value)”值。

if (x > 0) { 1
} else if (x == 0) 0 else -1

完整的if/else中,如果要在else之前换行,需要用{}
Scala中没有提供switch,可以使用一组if替代。

2.2 语句终止符

Java和C++中,语句结尾需要一个分号。Scala中,如果语句在换行时结束,则不需要分号。

if (n > 0) { r = r * n; n -= 1 }

同一行中,如果有多个语句,需要分号分隔。

scala> if (a >= 7){
     | a = a * a
     | a -= 1
     | }

如果一个语句有多行,可以用{}包起来。

2.3 块表达式(Block Expressions)和赋值

val distance = { val dx = x - x0; val dy = y - y0; sqrt(dx * dx + dy * dy) }

一个{}块,包含一系列的表达式。块的值是最后一个表达式的值。

scala> var x = y = 1
x: Unit = ()

Scala中,赋值语句的值是Unit类的值()

2.4 输入输出

scala> print("Answer:")
Answer:
scala> println("7")
7

scala> printf("Hello, %s! You are %d years old.\n", "Fred", 7)
Hello, Fred! You are 7 years old.

支持print, println, printf

scala> val myname = readLine("Your name: ")
Your name: myname: String = locusxt
scala> val age = readInt()
age: Int = 7

利用readLine接受一个字符串,类似的还有readInt, readDouble, readByte, readShort, readLong, readFloat, readBoolean, readChar

warning: there was one deprecation warning; re-run with -deprecation for details

实际使用中,会报warning,说方法已经过时。在import scala.io.StdIn._之后,可以避免warning

2.5 循环

while (n > 0) { r=r* n
n -= 1
}

while循环与Java和C++中一致。
Scala没有提供,(initialize; test; update)形式的for循环。Scala中的for循环:

for (i <- expr)

i遍历所有expr中的值。

for (i <- 1 to n) 
    r=r* i
for (i <- 0 until s.length)
    sum += s(i)

tountil的差别在于,to包括上界,until不包括上界。

2.6 循环进阶

for (i <- 1 to 3; j <- 1 to 3) print((10 * i + j) + " ") 
// Prints 11 12 13 21 22 23 31 32 33

允许有多个循环变量。

for (i <- 1 to 3; j <- 1 to 3 if i != j) print((10 * i + j) + " ")
// Prints 12 13 21 23 31 32

每个条件变量允许有一个guard,即Boolean型的if条件判断,if之前不需要分号。

for (i <- 1 to 3; from = 4 - i; j <- from to 3) print((10 * i + j) + " ") 
// Prints 13 22 23 31 32 33

循环内,可以引入任意数量的定义。

scala> for (i <- 1 to 10) yield i % 3
res0: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 0, 1, 2, 0, 1, 2, 0, 1)

如果for循环的body部分以yield开始,则构建一个集合(collection)。这种类型称作for comprehension

for (c <- "Hello"; i <- 0 to 1) yield (c + i).toChar 
// Yields "HIeflmlmop"
for (i <- 0 to 1; c <- "Hello") yield (c + i).toChar
// Yields Vector('H', 'e', 'l', 'l', 'o', 'I', 'f', 'm', 'm', 'p')

生成的集合的形式与第一个循环变量有关。

for { i <- 1 to 3
    from = 4 - i
    j <- from to 3 }

for循环还可以写成上面这种形式。

2.7 函数

方法(method)是对对象的操作,函数(function)则不同。

def abs(x: Double) = if (x >= 0) x else -x

Scala中,函数的定义方式如上。需要具体说明参数的类型,返回值的类型不需要说明。

def fac(n : Int) = {
    var r = 1
    for (i <- 1 to n) r = r * i
    r
}

函数有多个语句时,使用块。函数返回值,就是块的最后一个表达式。
Scala中一般不使用return关键字。

def fac(n: Int): Int = if (n <= 0) 1 else n * fac(n - 1)

对于一个递归函数,需要说明返回值的类型。

2.8 默认参数

def decorate(str: String, left: String = "[", right: String = "]") = 
    left + str + right

leftright有默认参数。

decorate(left = "<<<", str = "Hello", right = ">>>")
decorate("Hello", right = "]<<<") // Calls decorate("Hello", "[", "]<<<")

2.9 可变参数

def sum(args: Int*) = {
    var result = 0
    for (arg <- args) result += arg
    result
}
val s = sum(1, 4, 9, 16, 25)

这个函数可以接受任意个数的参数。

val s = sum(1 to 5) // Error
val s = sum(1 to 5: _*) // Consider 1 to 5 as an argument sequence

值序列不能直接传给函数,增加: _*,让参数被认为是一个参数序列。

2.10 过程(Procedures)

def box(s : String) { // Look carefully: no = 
    val border = "-" * s.length + "--\n" 
    println(border + "|" + s + "|\n" + border)
}

procedure定义时不需要=,返回值是Unit,没有值。

def box(s : String): Unit = { 
    ...
}

也可以写作上面这种形式。

2.11 Lazy Values

lazy val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString

当一个val被declare为lazy时,它在被首次使用时,才会初始化。

2.12 异常

throw new IllegalArgumentException("x should not be negative")

throw语句的类型为Nothing

try {
    process(new URL("http://horstmann.com/fred-tiny.gif"))
} catch {
    case _: MalformedURLException => println("Bad URL: " + url) 
    case ex: IOException => ex.printStackTrace()
}

var in = new URL("http://horstmann.com/fred.gif").openStream() 
try {
    process(in) 
} finally {
    in.close() 
}

你可能感兴趣的:(scala)