您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關Scala 方法和函數的區別是什么,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
Scala中既有函數(Function)也有方法(Method),大多數情況下我們都可以不去理會他們之間的區別。但是有時候我們必須要了解他們之間的不同。
Scala 中的方法跟 Java 的方法一樣,方法是組成類的一部分。方法有名字、類型簽名,有時方法上還有注解,以及方法的功能實現代碼(字節碼)。
Scala 中的函數是一個完整的對象。Scala 中用 22 個特質(trait)抽象出了函數的概念。這 22 特質從 Function1 到 Function22:
如上圖中的 Function10 代表的是:有 10 個形參,返回值為 R(協變)的函數。
函數更常使用的是匿名函數,定義的時候只需要說明輸入參數的類型和函數體即可,不需要名稱如果你要是用的話,一般會把這個匿名函數賦值給一個變量(其實是val常量)
表現形式:(傳入參數)=>{方法體}
val f = (name:String)=>println("Hi,"+name) f("kafka")
Scala 中的函數其實就是繼承了這些 Trait 的類的對象,如:我們通過函數字面量定義一個函數
其實上述函數的定義方式跟如下定義方式等同:
由于 Function2 是特質,不能直接 new。上述 new Function2[Int,Int,Int](){} 其實是定義并實例化一個實現了 Function2 特質的類的對象。
apply 是 scala 中的語法糖:對一個對象 obj 上調用 obj(),scala 編譯器會轉換為 obj.apply();在一個類 clazz 上調 clazz(),scala 編譯器會轉換為 clazz_company_obj.apply(),其中 clazz_company_obj 為 clazz 的伴生對象。
具體的差異,總結為如下幾點:
1. 方法不能作為單獨的表達式而存在(參數為空的方法除外),而函數可以。如:
scala> def m(x:Int) = 2.0*x m: (x: Int)Double 方法的定義 scala> val f = (x:Int)=> 2.0*x f: Int => Double = <function1> 函數定義 scala> f res7: Int => Double = <function1> 函數就是 scala> val tmp = m _ 通過這個方式還可以實現方法到函數的變化 tmp: Int => Double = <function1> scala> m 直接調用方法名是錯誤的 <console>:13: error: missing argument list for method m Unapplied methods are only converted to functions when a function type is expected. You can make this conversion explicit by writing `m _` or `m(_)` instead of `m`. m ^ 在Scala語言中, 函數也是對象, 每一個對象都是scala.FunctionN(1-22)的實例, 其中N是函數參數的數量, 例如我們定義一個函數并復制給一個變量: scala> val f = (x: Int) => x + 1 (匿名函數的寫法) f: Int => Int = <function1> 這里定義了一個接收一個整型變量作為參數的函數, 函數的功能是返回輸入參數加1. 可以看到REPL返回參數的toString方法 即 <function0> . 那么如果我們有一個指向函數對象的引用, 我們該如何調用這個函數呢? 答案是通過FunctionN的 apply 方法, 即 FunctionN.apply() , 因此調用函數對象的方法如下: scala> f.apply(3) res2: Int = 4 但是如果每次調用方法對象都要通過FunctionN.apply(x, y...), 就會略顯啰嗦, Scala提供一種模仿函數調用的格式來調用函數對象 scala> f(3) res3: Int = 4
在如上的例子中,我們首先定義了一個方法 m,接著有定義了一個函數f。接著我們把函數名(函數值)當作最終表達式來用,由于f本身就是一個對象(實現了 FunctionN 特質的對象),所以這種使用方式是完全正確的。但是我們把方法名當成最終表達式來使用的話,就會出錯。
2.方法可以沒有參數列表而 函數必須要有參數列表
scala> def m1 = 100 m1: Int 沒有入參的方法定義 是下面的簡寫形式 scala> def m2() = 100 m2: ()Int 無入參的放到定義 scala> val f1 = ()=>100 無入參的函數定義 f1: () => Int = <function0> scala> val f1 = => 100 仿照最上面寫就直接報錯 <console>:1: error: illegal start of simple expression val f1 = => 100
在如上的例子中,m1方法接受零個參數,所以可以省略參數列表。而函數不能省略參數列表。
3.方法名是方法調用,而函數名只是代表函數對象本身
這個比較容易理解。因為保存函數字面量的變量(又稱為函數名或者函數值)本身就是實現了 FunctionN 特質的類的對象,要調用對象的 apply方法,就需要使用obj()的語法。所以函數名后面加括號才是調用函數。如下:
scala> def m1 = 100 m1: Int 方法定義 scala> val f1 = ()=> 100 函數定義 f1: () => Int = <function0> scala> m1 方法調用 res11: Int = 100 scala> f1 函數查看 res12: () => Int = <function0> scala> f1() 函數調用,是下面調用方式的簡單版 res13: Int = 100 scala> f1.apply() 函數調用的正確形式 res14: Int = 100
4.在需要函數的地方,如果傳遞一個方法,會自動進行ETA展開(把方法轉換為函數)
如上,如果我們直接把一個方法賦值給變量會報錯。如果我們指定變量的類型就是函數,那么就可以通過編譯,如下:
scala> val f1:(Int)=>Int = m f1: Int => Int = <function1>
當然我們也可以強制把一個方法轉換給函數,這就用到了 scala 中的部分應用函數:
scala> val f1 = m _ f1: Int => Int = <function1> scala> val f1 = m(_) f1: Int => Int = <function1>
5.傳名參數本質上是個方法
傳名參數實質上是一個參數列表為空的方法,因為函數的話參數列表是不能為空的!(區別2參考),如下:
scala> def m1(x: =>Int) = List(x,x) m1: (x: => Int)List[Int]
如上代碼實際上定義了一個方法 m1,m1 的參數是個傳名參數(方法)。由于對于參數為空的方法來說,方法名就是方法調用 ,所以List(x,x)實際上是進行了兩次方法調用。
由于 List(x,x) 是進行了兩次方法調用,所以得到兩個不同的值。如果我們稍微修改一下函數的m1的定義,把x先緩存起來,結果就會跟以前大不一樣。
scala> def m1(x: => Int) = {val y = x;List(y,y)} m1: (x: => Int)List[Int] scala> m1(r.nextInt) res18: List[Int] = List(-723271792, -723271792)
6. 方法跟函數當參數的調用
// 方法定義 def method1(arge1: Int, arge2: Int) = arge1 + arge2 // 函數定義 val funct1 = (arge1: Int, arge2: Int) => arge1 - arge2 def method2(f: (Int, Int) => Int) = f(12, 12) println("方法傳方法" + method2(method1)) val funct2 = (f: (Int, Int) => Int) => f(22, 22) println("函數傳方法" + funct2(method1)) def method3(f: (Int, Int) => Int) = f(4, 1) println("方法傳函數" + method3(funct1)) val funct3 = (f: (Int, Int) => Int) => f(5, 1) println("函數傳函數" + funct3(funct1)) -------------------------------------------------------------------------------------- // 調用方式一 方法調用方法 def method1(): Unit = println("printmethod1") def method2(m: () => Unit): Unit = m() // 如果參數列表寫的是帶() 調用的時候也要帶() method2(method1) //執行 // 調用方式二 方法調用方法 def method11: Unit = println("printmethod11") def method22(m: => Unit) = m // 如果參數列表中 就沒有() 此處不可寫m() method22(method11) //執行 //調用方式三 def method111(): Unit = println("printmethod111") def method222(m: () => Unit) = m // 如果參數列表帶() 調用時候不帶(),則不會執行 method222(method111) //此處沒有輸出
Scala 中Apply講解
class ApplyTest{ def apply() = println("I am into Spark so much!!!") def haveATry{ println("Have a try on apply!") } } object ApplyTest{ def apply() = { println("I am into Scala so much!!!") new ApplyTest } } object ApplyOperation { def main(args: Array[String]) { val array = Array(1,2,3,4,5) val a = ApplyTest() //這里并沒有new,然后確實返回了類的實例 a.haveATry } }
輸出結果:
I am into Scala so much!!! Have a try on apply!
在一個類的伴生對象里面,實現apply方法,在這里面可以創建類的實例。譬如val a = Array(1, 2, 3)就是使用了Array的apply方法。
同樣,在class里面也可以使用apply方法:
object ApplyOperation { def main(args: Array[String]) { val a = new ApplyTest a.haveATry println(a()) //調用class的apply方法 } }
結果:
Have a try on apply! I am into Spark so much!!! ()
上述就是小編為大家分享的Scala 方法和函數的區別是什么了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。