目录
函数的定义和使用
def 方法名(参数名:参数类型): 返回值类型 = {
// 括号内的叫做方法体
// 方法体内的最后一行为返回值,不需要return
}
- 若有返回值, 方法体内的最后一行为返回值,不需要return
- 若不要返回值,则返回值类型是Unit
- = 后面是有{}的但是我们只有一行,{}可以不写
- 若程序可以推断出返回值类型,则返回值类型也可以不写
-
scala的特别之处,方法没有入参,调用时()可以不写
object FunctionApp {
def main(args: Array[String]): Unit = {
println(add(1, 4))
println(add())
println(add) // scala的特别之处,方法没有入参,调用时()可以不写
sayHello()
sayHello("Amy")
}
def add(x: Int, y: Int): Int = {
x + y // 最后一行就是返回值,不需要return语句
}
def add(x: Int): Int = x + 1 // = 后面是有{}的但是我们只有一行,可以不写
def add() = 1 + 2 // 返回值类型也没有写,因为底层可以推断
def sayHello(): Unit = println("Say hello ..... ")
def sayHello(name: String) = println("Say hello ..... " + name)
}
默认参数
在函数定义的时候,允许指定默认值。但是默认参数,也是可以传入参的,所以,即使调用时不传参,()也不可以省略。
object FunctionApp {
def main(args: Array[String]): Unit = {
sayHello("xuanshuang")
// sayName // 报错,尽管有默认值,可以不传参,但依旧有参数列表,()不可以省略
sayName()
sayName("Lily")
}
def sayHello(name: String) = println("Say hello ..... " + name)
// def sayHello(name: String = "xuanshuang") = { //报错,sayHello已定义
// println("Say hello ..... " + name)
// }
def sayName(name: String = "Amy") = println("Say hello ..... " + name)
}
命名参数
命名参数:在函数调用的时候可以不按照顺序传值,可以通过名字把值传给函数
- 调用的时候可以以行参=xxx(命名参数)的方式传值,这样打乱顺序传值,也能正确运行
- scala还可以在顺序传值的时候借用命名参数传值,与其他语言的区别之处,顺序传值后面的可以直接传值,不需要借助命名参数
- 若非顺序传值,第一个命名参数之后都必须命名参数传值
- 与默认参数组合使用时,命名参数显得更加有用
object FunctionApp {
def main(args: Array[String]): Unit = {
println(speed(100, 10, "Amy"))
println(speed(100, time = 10, "Jack"))
// println(speed(time =100, distance = 10, "palne")) //报错,Positional after named argument
println(speed(distance=100, time = 10, "xs"))
}
def speed(distance: Float, time: Float, name: String )={
name + "," + (distance / time)
}
}
可变参数
- 与Java一样,方法重载时,可变参数列表所在的方法是最后被访问的
- 与Java一样,可变列表一定要放在最后。即不可以def concat(words: Char*, a: Int)
- 正因为可变列表一定要放在最后,所以一个方法只能有一个可变参数
- 命名参数和默认参数当前在可变参数列表组合使用时,有如下特性——无法修改命名参数的定义顺序,建议尽量避免组合使用命名参数和可变参数。
object FunctionApp {
def main(args: Array[String]): Unit = {
// 这边强转会将数字转成对应的ASII码代表的字符,
println(concat(65.asInstanceOf[Char],'h', 'e', 'l', 'l', 'o'))
println(concat())
println(concat('h', 'e')) // 和Java类似,双参和可变参数的concat方法均能匹配时,优先匹配双参
}
def concat(words: Char*): String ={
var result: String = "可变参数,result is :"
for(word <- words){
result += word
}
result
}
def concat(one: Char, two: Char) = "双参,result is :" + one + two
}
class Family(mom: String, dad: String, kids: String*)
object NamedDefaultFlexibleArgs {
def main(args: Array[String]): Unit ={
new Family(mom="mom", dad="dad")
// Error:when using named arguments, the vararg parameter has to be specified exactly once
// new Family(dad="dad", mom="mom")
//命名参数和默认参数当前在可变参数列表组合使用时,有如下特性——无法修改命名参数的定义顺序
// new Family(dad="dad", mom="mom")
}
}
作为对象的函数
方法是依附于类或对象的,而函数是其自身的对象(这就是为啥我们可以如此容易的传递它)。当作参数传递给其他方法或函数的函数通常都非常小,且往往只使用一次。可以定义一个匿名函数。
- 匿名函数时使用=>符号定义的,=>左边是参数列表,右边是单个表达式(可以是组合表达式)。
- 若是多个参数,就必须对参数列表使用括号
- 只有一个参数,且Scala可以推断出该参数的类型,则可以去掉括号和参数类型。
// Later类接受一个具有0个参数的函数作为参数,
// 使用匿名函数的方式定义的,无任何参数(),一个=>和Unit合起来
class Later(val f: () => Unit){
def call():Unit = {f()}
}
object Anonymous {
def main(args: Array[String]): Unit ={
val v1 = Vector("hello", "Scala")
// 匿名函数时使用=>符号定义的,=>左边是参数列表,右边是单个表达式(可以是组合表达式)
v1.foreach((n: String) => {print(n + " -> ")})
println()
val v2 = Vector(1, 2, 3)
// 只有一个参数,且Scala可以推断出该参数的类型,则可以去掉括号和参数类型。
v2.foreach(n => print(n + " -> "))
println()
println("=========================")
val later = new Later(() => println("now"))
later.call()
val later1 = ()=>println("hi")
// 报错:later1() Unit does not take parameters
// val later2 = println
// later2()
}
}
匿名函数
- 匿名函数是使用=>符号定义的,=>左边是参数列表,右边是单个表达式(可以是组合表达式)
- 只有一个参数,且Scala可以推断出该参数的类型,则可以去掉括号和参数类型。
我们在下面的例子中,
- 将匿名函数以参数列表的形式传递给Later类,当该类的实例化对象调用call方法时会调用该匿名函数。其中若call(),则调用可以选择是否加括号,若call,调用时不能用括号
- 在主函数中定义了函数def later1 = ()=>println("hi 1"),通过later1()可调用,later1没输出
-
val later2 = ()=>println("hi 2"),通过later2()调用,later2没输出
// Later类接受一个具有0个参数的函数作为参数,
// 使用匿名函数的方式定义的,无任何参数(),一个=>和Unit合起来
class Later(val f: () => Unit){
def call():Unit = {f()}
}
object Anonymous {
def main(args: Array[String]): Unit ={
val v1 = Vector("hello", "Scala")
// 匿名函数是使用=>符号定义的,=>左边是参数列表,右边是单个表达式(可以是组合表达式)
v1.foreach((n: String) => {print(n + " -> ")})
println()
val v2 = Vector(1, 2, 3)
// 只有一个参数,且Scala可以推断出该参数的类型,则可以去掉括号和参数类型。
v2.foreach(n => print(n + " -> "))
println()
println("=========================")
val later = new Later(() => println("now"))
later.call()
later.call
def later1 = ()=>println("hi 1")
later1()
later1 // 没有输出
val later2 = ()=>println("hi 2")
later2 // 没有输出
later2()
val later3 = println
later3 // 无输出
// later3() // 报错:later3() Unit does not take parameters
}
}
条件表达式
下例中,整个if就是一个表达式,因此它会产生一个结果
scala> val x = -1//x: Int = -1
scala> val a = if(x >0 )true else false //a: Boolean = false
循环表达式
- to: 左闭右闭
- range:左闭右开
- until:左闭右开
object FunctionApp {
def main(args: Array[String]): Unit = {
for(i <- 1.to(5)) print(i + " ")
println()
for(i <- 1.until(5) if i % 2 == 0) print(i + " ")
println()
for(i: Int <- Range(5, 1, -2)) print(i + " ")
println("\n=================================")
val courses = Array("Hadoop", "Spark SQL", "Storm", "Scala", "Spark Streaming")
for(course <- courses) print(course + " ")
println()
courses.foreach(print)
println()
//course 其实就是courses里面的每个元素
// =>将左边的函数作用上一个函数变成另一个结果
// print就是作用到course伤的一个函数
courses.foreach(course => print(course + " "))
println("\n=================================")
var (num, sum) = (100, 0)
while(num > 0){
sum = sum + num
num -= 1
}
println("100 + 99 + ... + 2 + 1 = " + sum)
}
}
组合表达式
下例中组合表达式的结果作为isOpen的值,自然,类似println这样的表达式并不会产生结果,组合表达式也并非必须产生结果
val hour = 6
val isOpen={
val opens = 9
val closes = 20
println("Operating hour: " + opens + " - " + closes)
if(hour >= opens && hour <= closes){
true
}else{
false
}
}
参考:慕课网-学习Scala进击大数据Spark生态圈,收获高薪未来