這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)Scala 方法和函數(shù)的區(qū)別是什么,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
成都創(chuàng)新互聯(lián)公司是一家以成都網(wǎng)站建設(shè)公司、網(wǎng)頁設(shè)計(jì)、品牌設(shè)計(jì)、軟件運(yùn)維、營銷推廣、小程序App開發(fā)等移動(dòng)開發(fā)為一體互聯(lián)網(wǎng)公司。已累計(jì)為成都服務(wù)器托管等眾行業(yè)中小客戶提供優(yōu)質(zhì)的互聯(lián)網(wǎng)建站和軟件開發(fā)服務(wù)。
Scala中既有函數(shù)(Function)也有方法(Method),大多數(shù)情況下我們都可以不去理會(huì)他們之間的區(qū)別。但是有時(shí)候我們必須要了解他們之間的不同。
Scala 中的方法跟 Java 的方法一樣,方法是組成類的一部分。方法有名字、類型簽名,有時(shí)方法上還有注解,以及方法的功能實(shí)現(xiàn)代碼(字節(jié)碼)。
Scala 中的函數(shù)是一個(gè)完整的對(duì)象。Scala 中用 22 個(gè)特質(zhì)(trait)抽象出了函數(shù)的概念。這 22 特質(zhì)從 Function1 到 Function22:
如上圖中的 Function10 代表的是:有 10 個(gè)形參,返回值為 R(協(xié)變)的函數(shù)。
函數(shù)更常使用的是匿名函數(shù),定義的時(shí)候只需要說明輸入?yún)?shù)的類型和函數(shù)體即可,不需要名稱如果你要是用的話,一般會(huì)把這個(gè)匿名函數(shù)賦值給一個(gè)變量(其實(shí)是val常量)
表現(xiàn)形式:(傳入?yún)?shù))=>{方法體}
val f = (name:String)=>println("Hi,"+name) f("kafka")
Scala 中的函數(shù)其實(shí)就是繼承了這些 Trait 的類的對(duì)象,如:我們通過函數(shù)字面量定義一個(gè)函數(shù)
其實(shí)上述函數(shù)的定義方式跟如下定義方式等同:
由于 Function2 是特質(zhì),不能直接 new。上述 new Function2[Int,Int,Int](){} 其實(shí)是定義并實(shí)例化一個(gè)實(shí)現(xiàn)了 Function2 特質(zhì)的類的對(duì)象。
apply 是 scala 中的語法糖:對(duì)一個(gè)對(duì)象 obj 上調(diào)用 obj(),scala 編譯器會(huì)轉(zhuǎn)換為 obj.apply();在一個(gè)類 clazz 上調(diào) clazz(),scala 編譯器會(huì)轉(zhuǎn)換為 clazz_company_obj.apply(),其中 clazz_company_obj 為 clazz 的伴生對(duì)象。
具體的差異,總結(jié)為如下幾點(diǎn):
1. 方法不能作為單獨(dú)的表達(dá)式而存在(參數(shù)為空的方法除外),而函數(shù)可以。如:
scala> def m(x:Int) = 2.0*x m: (x: Int)Double 方法的定義 scala> val f = (x:Int)=> 2.0*x f: Int => Double = <function1> 函數(shù)定義 scala> f res7: Int => Double = <function1> 函數(shù)就是 scala> val tmp = m _ 通過這個(gè)方式還可以實(shí)現(xiàn)方法到函數(shù)的變化 tmp: Int => Double = <function1> scala> m 直接調(diào)用方法名是錯(cuò)誤的 <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語言中, 函數(shù)也是對(duì)象, 每一個(gè)對(duì)象都是scala.FunctionN(1-22)的實(shí)例, 其中N是函數(shù)參數(shù)的數(shù)量, 例如我們定義一個(gè)函數(shù)并復(fù)制給一個(gè)變量: scala> val f = (x: Int) => x + 1 (匿名函數(shù)的寫法) f: Int => Int = <function1> 這里定義了一個(gè)接收一個(gè)整型變量作為參數(shù)的函數(shù), 函數(shù)的功能是返回輸入?yún)?shù)加1. 可以看到REPL返回參數(shù)的toString方法 即 <function0> . 那么如果我們有一個(gè)指向函數(shù)對(duì)象的引用, 我們?cè)撊绾握{(diào)用這個(gè)函數(shù)呢? 答案是通過FunctionN的 apply 方法, 即 FunctionN.apply() , 因此調(diào)用函數(shù)對(duì)象的方法如下: scala> f.apply(3) res2: Int = 4 但是如果每次調(diào)用方法對(duì)象都要通過FunctionN.apply(x, y...), 就會(huì)略顯啰嗦, Scala提供一種模仿函數(shù)調(diào)用的格式來調(diào)用函數(shù)對(duì)象 scala> f(3) res3: Int = 4
在如上的例子中,我們首先定義了一個(gè)方法 m,接著有定義了一個(gè)函數(shù)f。接著我們把函數(shù)名(函數(shù)值)當(dāng)作最終表達(dá)式來用,由于f本身就是一個(gè)對(duì)象(實(shí)現(xiàn)了 FunctionN 特質(zhì)的對(duì)象),所以這種使用方式是完全正確的。但是我們把方法名當(dāng)成最終表達(dá)式來使用的話,就會(huì)出錯(cuò)。
2.方法可以沒有參數(shù)列表而 函數(shù)必須要有參數(shù)列表
scala> def m1 = 100 m1: Int 沒有入?yún)⒌姆椒ǘx 是下面的簡(jiǎn)寫形式 scala> def m2() = 100 m2: ()Int 無入?yún)⒌姆诺蕉x scala> val f1 = ()=>100 無入?yún)⒌暮瘮?shù)定義 f1: () => Int = <function0> scala> val f1 = => 100 仿照最上面寫就直接報(bào)錯(cuò) <console>:1: error: illegal start of simple expression val f1 = => 100
在如上的例子中,m1方法接受零個(gè)參數(shù),所以可以省略參數(shù)列表。而函數(shù)不能省略參數(shù)列表。
3.方法名是方法調(diào)用,而函數(shù)名只是代表函數(shù)對(duì)象本身
這個(gè)比較容易理解。因?yàn)楸4婧瘮?shù)字面量的變量(又稱為函數(shù)名或者函數(shù)值)本身就是實(shí)現(xiàn)了 FunctionN 特質(zhì)的類的對(duì)象,要調(diào)用對(duì)象的 apply方法,就需要使用obj()的語法。所以函數(shù)名后面加括號(hào)才是調(diào)用函數(shù)。如下:
scala> def m1 = 100 m1: Int 方法定義 scala> val f1 = ()=> 100 函數(shù)定義 f1: () => Int = <function0> scala> m1 方法調(diào)用 res11: Int = 100 scala> f1 函數(shù)查看 res12: () => Int = <function0> scala> f1() 函數(shù)調(diào)用,是下面調(diào)用方式的簡(jiǎn)單版 res13: Int = 100 scala> f1.apply() 函數(shù)調(diào)用的正確形式 res14: Int = 100
4.在需要函數(shù)的地方,如果傳遞一個(gè)方法,會(huì)自動(dòng)進(jìn)行ETA展開(把方法轉(zhuǎn)換為函數(shù))
如上,如果我們直接把一個(gè)方法賦值給變量會(huì)報(bào)錯(cuò)。如果我們指定變量的類型就是函數(shù),那么就可以通過編譯,如下:
scala> val f1:(Int)=>Int = m f1: Int => Int = <function1>
當(dāng)然我們也可以強(qiáng)制把一個(gè)方法轉(zhuǎn)換給函數(shù),這就用到了 scala 中的部分應(yīng)用函數(shù):
scala> val f1 = m _ f1: Int => Int = <function1> scala> val f1 = m(_) f1: Int => Int = <function1>
5.傳名參數(shù)本質(zhì)上是個(gè)方法
傳名參數(shù)實(shí)質(zhì)上是一個(gè)參數(shù)列表為空的方法,因?yàn)楹瘮?shù)的話參數(shù)列表是不能為空的!(區(qū)別2參考),如下:
scala> def m1(x: =>Int) = List(x,x) m1: (x: => Int)List[Int]
如上代碼實(shí)際上定義了一個(gè)方法 m1,m1 的參數(shù)是個(gè)傳名參數(shù)(方法)。由于對(duì)于參數(shù)為空的方法來說,方法名就是方法調(diào)用 ,所以List(x,x)實(shí)際上是進(jìn)行了兩次方法調(diào)用。
由于 List(x,x) 是進(jìn)行了兩次方法調(diào)用,所以得到兩個(gè)不同的值。如果我們稍微修改一下函數(shù)的m1的定義,把x先緩存起來,結(jié)果就會(huì)跟以前大不一樣。
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. 方法跟函數(shù)當(dāng)參數(shù)的調(diào)用
// 方法定義 def method1(arge1: Int, arge2: Int) = arge1 + arge2 // 函數(shù)定義 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("函數(shù)傳方法" + funct2(method1)) def method3(f: (Int, Int) => Int) = f(4, 1) println("方法傳函數(shù)" + method3(funct1)) val funct3 = (f: (Int, Int) => Int) => f(5, 1) println("函數(shù)傳函數(shù)" + funct3(funct1)) -------------------------------------------------------------------------------------- // 調(diào)用方式一 方法調(diào)用方法 def method1(): Unit = println("printmethod1") def method2(m: () => Unit): Unit = m() // 如果參數(shù)列表寫的是帶() 調(diào)用的時(shí)候也要帶() method2(method1) //執(zhí)行 // 調(diào)用方式二 方法調(diào)用方法 def method11: Unit = println("printmethod11") def method22(m: => Unit) = m // 如果參數(shù)列表中 就沒有() 此處不可寫m() method22(method11) //執(zhí)行 //調(diào)用方式三 def method111(): Unit = println("printmethod111") def method222(m: () => Unit) = m // 如果參數(shù)列表帶() 調(diào)用時(shí)候不帶(),則不會(huì)執(zhí)行 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,然后確實(shí)返回了類的實(shí)例 a.haveATry } }
輸出結(jié)果:
I am into Scala so much!!! Have a try on apply!
在一個(gè)類的伴生對(duì)象里面,實(shí)現(xiàn)apply方法,在這里面可以創(chuàng)建類的實(shí)例。譬如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()) //調(diào)用class的apply方法 } }
結(jié)果:
Have a try on apply! I am into Spark so much!!! ()
上述就是小編為大家分享的Scala 方法和函數(shù)的區(qū)別是什么了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
文章標(biāo)題:Scala方法和函數(shù)的區(qū)別是什么
URL標(biāo)題:http://www.rwnh.cn/article24/pgspje.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、品牌網(wǎng)站制作、營銷型網(wǎng)站建設(shè)、電子商務(wù)、網(wǎng)站設(shè)計(jì)、網(wǎng)頁設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)