scala函数
函数是scala的核心
函数定义
def 函数名([参数列表]):[返回值]={
函数体
[表达式]
}
例如
def square(x: Int): Int = {
println(x)
x * x //不用写return,直接返回x*x
}
def sayHello(x:String):Unit={//Unit表示无返回值
println("Hello ! "+x)
}
传值调用
传值调用时,参数只在调用时计算一次,后续重复使用计算的结果
def square(x: Int): Int = {
println(x) //3
x * x //计算3*3
}
square(1+2) //先计算1+2
传名调用
传名调用时,参数在调用时不会计算,只有真正用到参数时才计算
def square(x: => Int): Int = {
println(x) //计算1+2
x * x //计算(1+2)*(1+2)
}
square(1+2) //调用时不计算
小练习:定义一个没有返回值的函数,实现输入一个整数,打印金字塔。
object TestDemo {
def fun(num:Int)={
for(i<- 1 to num){
for(j<- 1 to num-i){
print(" ")
}
for(j<- 1 to 2*i-1){
print("*")
}
println()
}
}
def main(args: Array[String]): Unit = {
fun(5)
}
}
打印结果
*
***
*****
*******
*********
命名参数
通常情况下,传入参数与函数定义的参数列表一一对应
命名参数允许使用任意顺序传入参数
def printName(first:String, last:String) = {
println(first + " " + last)
}
def main(args: Array[String]): Unit = {
printName("John","Smith")
printName(first = "John",last = "Smith")
printName(last = "Smith",first = "John")
}
//打印"John Smith"
参数缺省值
Scala函数允许指定参数的缺省值,从而允许在调用函数时不指明该参数
def printName(first:String="John", last:String="Smith") = {//相当于给了函数参数默认值
println(first + " " + last)
}
def main(args: Array[String]): Unit = {
printName()//不传值时,使用默认值,打印John Smith
printName(last = "ni")//打印John ni
printName(first = "hh")//打印hh Smith
printName("hh")//打印hh Smith,默认为first的值
}
匿名函数
指不含函数名称的函数
匿名函数定义
val 字面量 = (参数类型) => {函数体}
练习
定义一个去除字符串首尾空格的函数字面量trim
val trim = (str:String) => {
println(str.trim)
}
def main(args: Array[String]): Unit = {
trim(" a b c ")//打印"a b c"
}
定义一个截取字符串首字母的函数字面量initial
val initial= (str:String)=>{
println(str.head)
}
def main(args: Array[String]): Unit = {
initial("abcdefg")//打印"a"
}
高阶函数
高阶函数可以将其他函数作为参数或者使用函数作为输出结果
//函数作为参数
def doSquare(f:Int=>Int,p:Int)=f(p)
def square(x:Int):Int=x*x
doSquare(square,square(2))
//函数作为返回值
//返回类型为函数(Int=>Int)
def doSquare()={
(x:Int)=>x*x
}
doSquare()(2)
常用的高价函数
map、foreach、filter、fold、foldLeft、foldRight、reduce、zip、flatten、flatMap
详情见:scala方法大全
练习
编写函数values(fun:(Int)=>Int,low:Int,hight:Int)
该函数输出一个集合,对应给定区间内给定函数的输入和输出,比如values(x=>x*x,-5,5)将输出:
def values(fun:(Int) => Int,low:Int,hight:Int) ={
for(i:Int <- low to hight){
println(i,fun(i))//什么时候要用fun,就调fun
}
}
def main(args: Array[String]): Unit = {
//这里的x=>x*x就是fun:(Int)=>Int[匿名函数,参数一个,返回值一个]
values(x=>x*x,-5,5)
}
//直接用map实现
def main(args: Array[String]): Unit = {
(-5 to 5).map(x=>(x,x*x)).foreach(println)
}
函数嵌套
def main(args: Array[String]): Unit = {
//计算阶乘
def factorial(n: BigInt):BigInt ={
if (n<=1) 1
else n*factorial(n - 1)
}
for(i<- 1 to 10){
println(i+"的阶乘是"+factorial(i))
}
}
/*打印
1的阶乘是1
2的阶乘是2
3的阶乘是6
4的阶乘是24
5的阶乘是120
6的阶乘是720
7的阶乘是5040
8的阶乘是40320
9的阶乘是362880
10的阶乘是3628800
*/
柯里化(Currying)
方法可以定义多个参数列表,当使用较少的参数列表调用多参数列表的方法时,会产生一个新的函数,该函数接收剩余的参数列表作为其参数。这被称为柯里化
//单参数列表
def modN(n: Int,x: Int) = ((x % n) == 0)
//多参数列表
def modN(n: Int)(x: Int) = ((x % n) == 0)
//新函数接收剩余的参数列表作为其参数
def f1(x: Int) = modN(10)(x)
def f2(n: Int) = modN(n)(10)
def f3 = modN(10)(_)
隐式参数
隐式关键字:implicit
类似默认值
implicit var k = 40//隐式参数k
def abc(x:Int)(implicit y:Int) = x+y
def main(args: Array[String]): Unit = {
println(abc(10))//对于abc这个方法,只给出了x=10,而没有给y的值,此时,y会在类中寻找匹配类型的值,找到隐式参数k=40
}
//50
隐式函数
隐式关键字:implicit
implicit def stringToInt(st:String) = st.toInt//定义一个隐式函数,参数为String类型
def abc(x:Int)(y:Int) = x+y//定义一个普通韩式,参数为x和y
def main(args: Array[String]): Unit = {
println(abc(10)("60"))//对于abc这个方法,10赋给x,而y的对应类型是Int型,"60"是个String类型,通过stringToInt隐式函数,将"60"自动转换成Int类型,传给y
}
//70
隐式类
隐式关键字:implicit
implicit class MyExtend(num:Int){//定义一个隐式类,参数为Int型
var n:Int=num
def sayhi=println(s"Hello,$n")
}
def main(args: Array[String]): Unit = {
123.sayhi//无需new对象,这里的123相当于new MyExtend(123),匹配到MyExtend的参数类型,直接调用MyExtend的sayhi方法
}