第2章 控制结构和函数
2.1 条件表达式
在scala中if/else表达式有返回值,返回值是if或者else最后一行的值。例如:
if(x > 0) 1 else -1
上述表达式的返回值是1或-1,具体是哪一个取决于x的值。
if表达式的类型推断,由于if表达式是有值的,而if和else子句的值类型可能不同,此时if表达式的值是什么类型呢?Scala会自动进行推断,取两个类型的公共父类型。
if(age > 18) 0 else 1
自动推断返回值类型为 Int 类型
if(age > 18) “adult”else 1
自动推断返回值类型为 Any
如果if 后面没有跟else,则默认else的值是Unit,也用()表示,类似于java中的void或者null。例如:
val age = 12; if(age > 18) "adult",此时就相当于if(age > 18) "adult" else () 。
示例代码:
val lbs = 150.0
val height = 1.83
val weightStatus = {
val bmi = lbs/(height * height)
val result = if(bmi < 18.5) "Underweight"
else if(bmi < 25) "Normal weight"
else "Overweight"
print(result);
}
2.2 语句终止
在单行中写下多个语句,需要用分号隔开
if(n > 0){r = r * n; n -= 1}
在写较长的语句,需要分两行来写的话,要确保第一行以一个不能用做语句结尾分符号结尾,通常来说是操作符
s = s0 +
v * t
2.3 块表达式和赋值
在scala中,{}块包含一系列表达式,其结果也是一个表达式。块中最后一个表达式的值就是块的值。
val distance = {
val dx = x - x0
val dy = y - y0
sqrt(dx * dx + dy * dy)
}
2.4 输入与输出
输出有print和println函数,后者在打印完内容后会追加个换行符。例如:
print("Answer:")
println(42)
或
println("Answer:" + 42)
或
println("Answer:%d", 42)
输入有readLine函数从控制台读取一行输入。它可以带一个参数作为提示字符串,如过要读取的是数字、Boolean或字符,可以用readint、readDouble、readByte、readShort、readLong、readFloat、readBoolean或者readChar,但是不带参数。
2.5 循环
2.5.1 while循环
var temp = readInt scala.io.StdIn.readInt()
while(temp > 0) {
println(temp)
temp -= 1
}
2.5.2 for循环
for(c <- "Hello World") {
print(c)
}
2.5.3 yeild关键字,允许创建一个值去记录每一次迭代
for(c <- "Hello World") yield c
2.6 高级for循环和for推导式
for(i <- 1 to 3; j <- 1 to 3 if i != j) print ((10 * i + j) + " ")
注意:在if之前并没有分号
如果for循环的循环体以yield开始,则该循环会构造出一个集合,每次迭代生成集合中的一个值:
for (i <- 1 to 10) yield i % 3
这类循环叫做for推导式。
2.7 函数
优点:更好的管理程序;抽象和复用代码;Scala 提供了许多Java中没有的定义函数的方式。除了作为对象成员函数的方法之外,还有内嵌在函数中的函数,函数文本和函数值
def + 方法名(参数名 : 参数类型) : 返回类型 = {
//block内最后一行为返回值
}
当返回值为Unit时可以定义为: def 方法名(参数名 : 参数类型) {}
没有参数的方法可以不带圆括号
Scala没有静态方法,通过object来实现
Scala中定义函数时,需要定义函数的函数名、参数、函数体
Scala要求必须给出所有参数的类型,但是不一定给出函数返回值的类型,只要右侧的函数体中不包含递归的语句,Scala就可以自己根据右侧的表达式推断出返回类型
Scala 的函数是一等公民,不仅可以定义后被调用,还可以把它写成匿名的字面量,然后作为值进行传递。
函数的字面量被编译进类,并在运行期间实例化为函数值。
字面量是指=>右端的部分(即:函数的表达式)例如 x:Int => x 7 则x7 是函数字面量;函数字面量和函数值区别在于存在于源代码还是对象运行期间
任何函数值都是扩展了Scala 包的若干FunctionN特质之一的类的实例,如Function0 是没有参数的函数,每个FunctionN特质有一个apply 方法来调用函数。
如果想让函数字面量更加整洁,可以把下划线当做一个或更多的参数占位符,只要每个参数在函数字面量内仅出现一次。
值函数:Scala的语法规定,将函数赋值给变量,并且在函数后面加上空格和下划线的形式
匿名函数:Scala中,不命名的函数。
高阶函数:接收其他函数作为参数的函数,被称作高阶函数
高阶函数的另外一个功能是将函数作为返回值
高阶函数可以自动推断出参数类型,调用时不需要写明类型①
对于只有一个参数的函数,调用时还可以省去其小括号②
如果仅有的一个参数在右侧的函数体内只使用一次,则还可以将接收参数省略,并且将参数用_来替代(下图中 main 函数分别展示了高阶函数的这些中写法,大家要熟悉)
部分应用函数:是一种表达式,无需提供部分应用函数所有的参数,只提供部分或者不提供
def add(x: Int, y: Int) = x + y
我们定义add 函数,将add 函数的部分应用表达式赋值给a,实例化一个带有两个缺失值的函数值并把新的函数值索引给变量a,当把函数值a应用于两个参数之上时,它将回头调用add并传入两个参数
val a = add _ //未使用所有参数
a(4,5)
原理:名为a的变量指向一个函数值对象。这个函数值是由Scala编译器依照偏应用函数表达式add _,自动产生的类的一个实例。编译器产生的类有一个apply方法带两个参数。Scala编译器把表达式a(4,5)翻译成对函数值的apply方法的调用,传入4,5。因此a(4,5) = a.apply (4,5)
函数 VS 方法:
参数列表对于方法是可选的,但是对于函数参数列表是强制的
方法可以没有参数列表,参数列表也可以为空;而函数必须有参数列表(也可以为空)。
方法名意味着方法调用,但函数名却代表的是函数自身。
方法可以自动(称之ETA扩展)或手动强制转换为函数;但是函数不可以转换成方法。
2.8 参数
默认参数:在定义函数时,被赋予初值的参数
带名参数:在调用函数时,在提供参数值的时候指定参数名
变长参数:在参数数据类型后面加上*
def sum (args: Int*) = {
var result = 0
for (arg <- args) result += arg
result
}
你可以使用任意多的参数来调用该函数。
_:用于将一个值的序列转化成参数序列
用法:s = sum(1 to 5: _)
2.9 过程
scala对于不返回值的函数有特殊的表达法。如果函数体包含在花括号中但没有前面的=,那么返回类型就是Unit,这样的函数叫过程。过程不返回值
2.10 懒值
当val被声明为lazy时,它的初始化将被推迟,直到对他首次取值
每当我们访问懒值都会调用一个以线程安全的方式检查该值是否已被初始化的方法
2.11 异常
单行Scala 异常机制和Java 类似,当抛出异常时,当前运算被截止
抛出的对象必须是 java.lang.Throwable 的子类
Scala 没有“受检”异常不需要声明函数可能会抛出某种异常
Scala 中捕获异常的组合通常是 try{…} catch{…} 或者是 try{…} finally{…}它们是互补的
try{…} catch{…} finally{…} 其实是 try{ try{…} catch{…} } finally{…} 的等价形式
try finally 组合 无论是否发生异常都能释放资源
如果URL 构造或openStream方法抛出异常,这样try代码块和finally 代码块都不会执行(这也没什么不好in 未初始化不需要close)
标签:函数,val,Scala,控制结构,else,参数,表达式 From: https://www.cnblogs.com/simpleness/p/17626129.html