Scala04 方法与函数
Scala 中的也有方法和函数的概念。
Scala中的 方法 是类的一部分。
Scala中的 函数 是一个对象,可以赋值给变量。
在类中定义的函数就是方法
4.1 方法
Scala 中方法 与 Java 中类似,是组成类的一部分
4.1.1 语法结构
格式:
def 方法名([参数列表]):[返回值类型] = {
方法体
rturn [结果]
}
rturn [结果] :返回的结果可以是任意合法的数据类型。
若没有返回值,则返回类型为“Unit”。
案例:定义方法用于计算两数之和
def add(a: Int, b: Int): Int = {
//定义变量 sum 用于接收两数相加
var sum: Int = 0
sum = a + b
return sum
}
4.1.2 方法调用
方式1:
functionName( 参数列表 )
案例:
object Test {
def main(args: Array[String]): Unit = {
println("结果:" + add(3, 2))
}
def add(a: Int, b: Int): Int = {
//定义变量 sum 用于接收两数相加
var sum: Int = 0
sum = a + b
return sum
}
}
方式2:
方法使用实例的对象来调用,我们可以使用类似java的格式 (使用 . 号):
[instance.]functionName( 参数列表 )
案例:
object Test {
def main(args: Array[String]) {
println("结果 : " + Test.add(2, 3));
}
def add(a: Int, b: Int): Int = {
//定义变量 sum 用于接收两数相加
var sum: Int = 0
sum = a + b
return sum
}
}
4.1.3 方法参数
- 可变参数(不定长参数)
// (1)可变参数
def test1(names:String*):Unit = {
println(s"你好 $names")
// 可变参数在函数值本质是一个数组
for (i <- names) {
println(i)
}
}
test1()
test1("张三")
test1("张三","李四")
- 默认参数(默认参数值)
// (2)参数默认值
def test2(name:String = "张三"):Unit = {
println(s"hi ${name}")
}
test2("王五")
test2()
- 指定参数(指定参数名进行传递)
// 默认值参数在使用的时候 可以不在最后
def test3(name: String = "李四", age: Int): Unit = {
println(s"姓名: ${name} 年龄:${age}")
}
// (4)带名参数
test3(age = 10)
3.1.4 方法注意
*方法定义可遵循至简原则:能省则省
(1)return可以省略,Scala会使用方法体的最后一行代码作为返回值
(2)如果方法体只有一行代码,可以省略花括号
(3)返回值类型如果能够推断出来,那么可以省略(和返回值类型一起省略)
注意事项:
*1. 如果有return,则不能省略返回值类型,必须指定
2. 如果方法明确声明unit,那么即使方法体中使用return关键字也不起作用
3. Scala如果期望是无返回值类型,可以省略等号(=号和方法体大括号不能同时省略)
4. 如果方法无参,但是声明了参数列表,那么调用时,小括号,可加可不加(声明无括号调用时也没有括号)
5. 如果方法没有参数列表,那么小括号可以省略,调用时小括号必须省略
4.2 函数
函数定义可以使用 val 和 def(在类中定义的函数就是方法) ,def 定义的形式和方法一样
4.2.1 语法结构
格式:
val 函数名 = ([参数列表]) => {
函数体
}
=> : 函数标识符
案例:定义函数用于计算两整数之和
//1、函数定义
val add = (a: Int, b: Int) => {
a + b
}
//2、函数调用
println(add(5, 5))
4.2.2 方法和函数区别
*1)方法定义在类中可以实现重载,函数不可以重载
2)方法是保存在方法区,函数是保存在堆中
3)定义在方法中的方法可以称之为函数,不可以重载
4)方法可以转成函数, 转换语法: 方法名 _ (方法名+空格+下划线)
- 方法 转换 为 函数 (方法名 _ ) / (方法名+空格+下划线)
//定义一个方法
def add(x:Int,y:Int) = x+y
//方法转成函数 (方法名+空格+下划线)
val add2 = add _
4.2.3 高阶函数
*高阶函数(Higher-Order Function)就是操作其他函数的函数
定义:参数/返回值为函数的方法/函数称为高阶函数
案例:
object TestFunction {
def main(args: Array[String]): Unit = {
// val func = new Function2[Int, Int, Int] {
// override def apply(v1: Int, v2: Int): Int = v1 + v2 // }
//定义函数
val func = (x: Int, y: Int) => x + y
//调用高阶函数
println(add(10, 20, func))
}
//def add( x:Int ,y:Int , func: Function2[Int,Int,Int] )
def add(x: Int, y: Int, func: (Int, Int) => Int) = {
func(x, y)
}
}
4.2.4 匿名函数
没有名字的函数/方法就是匿名函数。
格式:
(x:Int)=>{函数体}
案例:
var inc = (x:Int) => x+1
相当于:
def add2 = new Function1[Int,Int]{
def apply(x:Int):Int = x+1;
}
//TODO 匿名函数一般用于给高阶函数传值使用
m1(10,20,(x:Int,y:Int) => x+y )
def m1(x:Int,y:Int, func: (Int,Int)=>Int) = {
func(x,y)
}
4.2.5 闭包
*1. 闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的环境,称为闭包
2. 闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
3. 闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。
比如:val multiplier = (i:Int) => i * 10
案例:函数体内有一个变量 i,它作为函数的一个参数
在 multiplier 中有两个变量:i 和 factor。其中的一个 i 是函数的形式参数,然而,factor不是形式参数,而是函数外面定义的变量,
var factor = 3
val multiplier = (i:Int) => i * factor
4.2.6 函数柯里化
- 柯里化(Currying)指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数。
- 有多个参数列表的方法称之为柯里化
格式:
def 方法名(参数名:类型,...)(参数名:类型,...)...:返回值类型 = {方法体}
案例:
//定义普通函数 add
def add(x:Int,y:Int)=x+y
println(add(2,3))
在调用函数 add 时 写法为:add(2,3)
将刚才定义的函数 变形
def add(x:Int)(y:Int) = x + y
println(add(1)(2))
在调用函数 add 时 写法变为为:add(2)(3)
,这种方式(过程)就叫柯里化。
完整案例:
object Test {
def main(args: Array[String]) {
val str1:String = "Hello, "
val str2:String = "Scala!"
println( "str1 + str2 = " + strcat(str1)(str2) )
}
def strcat(s1: String)(s2: String) = {
s1 + s2
}
}
4.2.7 递归
*一个函数/方法在函数/方法体内又调用了本身,我们称之为递归调用
Scala 同 其他语言一样 也支持递归
格式:自己调用自己
def test()={
test()
}
注意事项:
- 递归要有跳出的逻辑(出口),不然会照常无限递归
- 递归有规律
- 递归必须要有函数返回值类型
案例:求数字 n 的 阶乘
object TestFunction {
def main(args: Array[String]): Unit = {
// 案例: 求 n 的阶乘.
print("几的阶乘:")
val n: Int = StdIn.readInt()
//2. 调用factor方法, 用来获取n的阶乘.
val num = factor(n)
//3. 打印结果.
println(num)
}
//1. 定义方法, 用来求数字n的阶乘.
def factor(n: Int): Int = if (n == 1) 1 else n * factor(n - 1)
}