Scala 有方法與函數,二者在語義上的區別很小。Scala 方法是類的一部分,而函數是一個對象,可以賦值給一個變量。換句話來說在類中定義的函數即是方法。Scala 中的函數則是一個完整的對象,Scala 中的函數其實就是繼承了 Trait 的類的對象。
Scala 中使用 val 語句可以定義函數,def 語句定義方法。
注意:有些翻譯上函數(function)與方法(method)是沒有區別的。
1、Scala方法/函數定義
object Test {
def main(args: Array[String]): Unit = {
fun(10, 20)
println(sum(10, 20))
println(sum2(30, 20))
}
def fun(a: Int, b: Int) = {
println("a=" + a)
println("b=" + b)
}
def sum(a: Int, b: Int) = a + b
def sum2(a: Int, b: Int): Int ={
return a + b
}
}
-
方法定義由一個 def 關鍵字開始,緊接着是可選的參數列表,一個冒號 : 和方法的返回類型,一個等於號 = ,最後是方法的主體。
-
如果方法沒有返回值,返回類型爲 Unit,類似於Java中的 void。方法可以寫返回值類型,也可以不寫,會自動推斷。有時候不能省略,比如在遞歸函數中、函數的返回類型是函數類型時,方法中寫return時等。
-
Scala中有返回值時,可以寫return,也可以不寫,函數會將最後一行作爲結果返回。
-
方法體可以一行搞定時,可以不寫 { } 。
-
Scala規定傳遞給方法的參數都是
常量val
的,不是var的。
2、Scala 函數傳名調用(call-by-name)
Scala的解釋器在解析函數參數(function arguments)時有兩種方式:
- 傳值調用(call-by-value):先計算參數表達式的值,再應用到函數內部;
- 傳名調用(call-by-name):將未計算的參數表達式直接應用到函數內部
object SayHello {
def main(args: Array[String]): Unit = {
println("傳值調用:")
delayed0(time())
println("===================")
println("傳名調用:")
delayed(time())
println("===================")
}
def time() = {
println("獲取時間,單位爲納秒")
System.nanoTime
}
def delayed0(t : Long)={
println("在 delayed0 方法內")
println("參數"+t)
t
}
def delayed(t: => Long) = {
println("在 delayed 方法內")
println("參數: " + t)
t
}
}
我們聲明瞭 delayed 方法, 該方法在變量名和變量類型使用 => 符號來設置傳名調用;輸出結果:
傳值調用:
獲取時間,單位爲納秒
在 delayed0 方法內
參數232873973675933
===================
傳名調用:
在 delayed 方法內
獲取時間,單位爲納秒
參數: 232873984381351
獲取時間,單位爲納秒
===================
簡言之,傳值調用會在調用方法前將參數的值計算出來,而傳名調用則是在方法調用後,在方法內部使用到參數地方調用。
3、Scala 閉包
閉包是一個函數,返回值依賴於聲明在函數外部的一個或多個變量。
閉包通常來講可以簡單的認爲是可以訪問一個函數裏面局部變量的另外一個函數。
我們引入一個自由變量 factor,這個變量定義在函數外面。
這樣定義的函數變量 multiplier 成爲一個"閉包",因爲它引用到函數外面定義的變量,定義這個函數的過程是將這個自由變量捕獲而構成一個封閉的函數。
實例:
object Test {
def main(args: Array[String]) {
var factor = 3
val multiplier = (i:Int) => i * factor
println( "muliplier(1) value = " + multiplier(1) )
println( "muliplier(2) value = " + multiplier(2) )
}
}
閉包的特性
- 1.函數嵌套函數
- 2.函數內部可以引用外部的參數和變量
- 3.參數和變量不會被垃圾回收機制回收
常見創建閉包的方式 就是函數內創建了函數
- 1.設置私有變量的方法
- 2.不適合的場景:返回閉包的函數是非常大的函數
- 3.缺點常駐內存,會增大內存的使用量,使用不當造成內存泄漏
爲什麼要使用閉包
- 1.想要得到函數內部的局部變量
- 2.只有函數內部的子函數才能讀取的函數內部的局部變量
- 3.閉包是函數內部和函數外部鏈接的橋樑
閉包的用途
- 可以讀取函數內部變量,可以讓變量的值始終保存在內存中
4、遞歸函數
必須制定 函數的返回類型
def fun(num :Int) :Int= {
if(num ==1)
num
else
num * fun2(num-1)
}
print(fun(4))
5、Scala 函數 - 默認參數值
object Test {
def main(args: Array[String]) {
println( "返回值 : " + addInt() );
}
def addInt( a:Int=5, b:Int=7 ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
}
6、Scala 函數 - 可變參數
Scala 通過在參數的類型之後放一個星號來設置可變參數(可重複的參數)。
object Test {
def main(args: Array[String]) {
printStrings("I", "Love", "Scala");
}
def printStrings( args:String* ) = {
var i : Int = 0;
for( arg <- args ){
println("Arg value[" + i + "] = " + arg );
i = i + 1;
}
}
}
7、Scala 函數 - 匿名函數
Scala 中定義匿名函數的語法很簡單,箭頭左邊是參數列表,右邊是函數體。
def main(args: Array[String]): Unit = {
value1()
value2(2)
println(value3(3,4))
println(value4(4,5))
}
// 無參匿名函數
val value1 = () => {
println("Hello word")
}
// 有參匿名函數
val value2 = (a: Int) => {
println(a)
}
// 多參 有返回
val value3 = (a: Int, b: Int) => {
a * b
}
val value4 = (a: Int, b: Int) => a * b
8、Scala 高階函數
高階函數(Higher-Order Function)就是操作其他函數的函數。
Scala 中允許使用高階函數, 高階函數可以使用其他函數作爲參數,或者使用函數作爲輸出結果。
以下實例中,apply() 函數使用了另外一個函數 f 和 值 v 作爲參數,而函數 f 又調用了參數 v:
object Test {
def main(args: Array[String]) {
println( apply( layout, 10) )
}
// 函數 f 和 值 v 作爲參數,而函數 f 又調用了參數 v
def apply(f: Int => String, v: Int) = f(v)
def layout[A](x: A) = "[" + x.toString() + "]"
}
apply()中 f 使用=>String, 表示是函數的傳名調用,傳入的函數會在該函數體使用的位置調用。