方法和函数的区别
1. 定义的语法不同
方法: def 方法名字(参数列表): 返回值类型 = { 方法体 }
函数: val 函数变量: 函数的类型(可以不设置) = (函数的参数列表) => { 函数体 }
2. 定义的位置不同
方法: 一般定义在类内、特质内、或者在某一个object内
函数: 一般定义在类内、特质内、object内、方法内
3.方法不能做为最终表达式出现,而函数可以
4. 方法名是方法调用,而函数名只是代表函数对象本身 (函数必须使用()进行调用才能执行)
5. 方法可以转换为函数,所以一般也不必严格区分
- 自动转换:在需要函数的地方,如果传递一个方法,Scala能够自动把方法转换为函数
- 手动转换:手动使用神奇的下划线_
将方法被转化成函数
# 不管方法和函数调用时加上()都没问题,以下情况除外
scala> def m0=1
m0: Int
scala> m0
res265: Int = 1
scala> m0()
<console>:15: error: Int does not take parameters
m0()
^
案例:
函数:
object Function {
def main(args: Array[String]): Unit = {
// 1. 定义一个Scala的函数
// Scala的函数是需要依靠某一个变量的
// 将这个函数给某一个变量进行赋值
// 此时 calculator就是一个变量,函数类型的变量
// (Int, Int) => Int
val calculator = (a: Int, b: Int) => a + b
// 2. 使用这个函数
println(calculator(10, 20))
// 3. 定义一个Scala的函数
// 如果左侧的函数变量的类型已经确定,在右侧的实现部分,可以不写参数的类型
val calculator2: (Int, Int) => Int = (x, y) => x + y
println(calculator2(10, 20))
// 4. 进阶1:
// 如果函数的实现中,参数只用到了一次,在实现部分,可以省略掉参数的声明部分,使用_来替代参数
// val calculator3: Int => Unit = x => println(x)
val calculator3: Int => Unit = println(_)
val calculator4: Int => Int = _ * 2
println(calculator4(10))
// 5. 进阶2:
// 如果函数的实现中,参数只用到了一次,在实现部分,可以省略掉参数的声明部分,使用_来替代参数
val calculator5: (Int, Int) => Int = _ + _
println(calculator5(10, 20))
val calculator6: (Int, Int, Int) => Int = _ + _ + _
println(calculator6(10, 20, 30))
// 6. 进阶3:
// 如果函数的实现中,使用_来表示唯一使用到参数
// 且这个参数,作为另外的一个函数或者方法的参数出现的
// 此时,可以省略掉这个下划线和方法或者参数的小括号
val calculator7: Int => Unit = println(_) //_作为println的参数
val calculator8: Int => Unit = println
// 7. 进阶4:
val calculator9: (Int, Int) => Int = calculateMethod
println(calculator9(10, 20))
// 8. 进阶5:
// 高阶函数,将一个参数或者返回值设置为其他的函数,就是一个高阶函数
//
// calculate(_ + _, 10, 20)
// calculate(calculator5, 100, 200)
// calculate(calculateMethod, 100, 200)
// 9. 进阶6:
// val cal: ((Int, Int)=>Int, Int, Int) => Unit = (calculator, x, y) => println(calculator(x, y))
val cal: ((Int, Int) => Int, Int, Int) => Int = _ (_, _)
cal(_ + _, 100, 200)
// 10. 方法转函数, 直接在后面添加一个空格下划线即可
val calculator10 = calculateMethod _
}
def calculate(calculator: (Int, Int) => Int, x: Int, y: Int): Unit = {
// calculator: 是一个函数类型的变量,提供了对两个数字进行运算的逻辑
// x
// y
println(calculator(x, y))
}
def calculateMethod(x: Int, y: Int): Int = x + y
}
方法:
/**
* 1. 在定义方法的时候,方法的返回值类型可以不写,可以由实际返回的值进行推导。[不推荐]
* 但是,有一个例外情况:当递归调用方法的时候,此时这个方法的返回值类型必须明确。
*
* 2. 如果方法体中的逻辑很简单,只有一行代码,此时大括号是可以省略不写的。而且,这种省略不写,是推荐的!
*
* 3. 如果一个方法是无参数的,在调用的时候可以不写小括号。[不推荐]
*
* 4. 如果一个方法是无参数的,在定义的时候可以省略小括号不写,此时在调用的时候,也不能写小括号。[不推荐]
*/
object Method {
def main(args: Array[String]): Unit = {
// 调用方法
myFirstMethod()
println(calculate(10, 20))
}
// 定义我的第一个方法
def myFirstMethod(): Unit = println("这是我的第一个scala方法")
def calculate(a: Int, b: Int): Int = a + b
//重载
def calculate(a: Int, b: Int, c: Int): Int = a + b + c
// 如果在定义方法的时候,可以不写等号
// 如果不写等号,此时不会通过右侧方法体的结果,来自动的推导方法的返回值类型,只适合没有返回值的方法
def myTestMethod() {
val a = 10
val b = 20
a + b
}
}
object Method2 {
def main(args: Array[String]): Unit = {
println(calculate(10, 20))
println(calculate(10, 20, 30))
//
println(calculate2(5, 10))
// 调用方法时,传参的时候,可以使用带名参数
println(calculate2(y = 10))
println(calculate2(y = 5, z = 10, x = 20))
}
// 在定义方法的时候,scala允许某些参数是有默认值的
// 有默认值的参数,在调用的时候,可以不进行值的设置
def calculate(x: Int, y: Int, z: Int = 10): Int = {
println(s"x = $x, y = $y, z = $z")
x + y + z
}
// 有默认值的参数,在进行方法的调用的时候,默认传递的值其实也是要按照顺序进行赋值的
def calculate2(x: Int = 10, y: Int, z: Int = 30): Int = {
println(s"x = $x, y = $y, z = $z")
x + y + z
}
}
object Method3 {
def main(args: Array[String]): Unit = {
println(getSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
// 拓展:
// 在Java中,变长参数可以直接传递一个数组值。但是在Scala中是不允许的
val array = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
getSum(array:_*)// 展开数组得到每一个元素
}
def getSum(numbers: Int*): Int = {
// 在scala中,变长参数的类型,也是数组类型的
var sum = 0
for (n <- numbers) {
sum += n
}
sum
}
//递归
def getFebonacci(index: Int): Int = {
if (index == 1 || index == 2) {
return 1 //写return因为此处不是整个结构的最后一句话
}
getFebonacci(index - 1) + getFebonacci(index - 2)
}
}
方法转函数:
scala> def m1(x:Int,y:Int) = x + y
m1: (x: Int, y: Int)Int
scala> val f1=m1 _ //方式一:方法被转化成函数
f1: (Int, Int) => Int = <function2>
scala> val f1=m1(_,_) //方式二:方法被转化成函数
f1: (Int, Int) => Int = <function2>
scala> val f1=m1 //不允许将方法直接赋值给变量,方法不是值,而函数与其他数据类型一样
<console>:12: error: missing argument list for method m1
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `m1 _` or `m1(_,_)` instead of `m1`.
val f1=m1
^