中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Scala 方法和函數的區別是什么

發布時間:2021-07-27 18:25:43 來源:億速云 閱讀:183 作者:Leah 欄目:大數據

這期內容當中小編將會給大家帶來有關Scala 方法和函數的區別是什么,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

Scala中既有函數(Function)也有方法(Method),大多數情況下我們都可以不去理會他們之間的區別。但是有時候我們必須要了解他們之間的不同。

Scala 中的方法跟 Java 的方法一樣,方法是組成類的一部分。方法有名字、類型簽名,有時方法上還有注解,以及方法的功能實現代碼(字節碼)。

Scala 中的函數是一個完整的對象。Scala 中用 22 個特質(trait)抽象出了函數的概念。這 22 特質從 Function1 到 Function22:

Scala 方法和函數的區別是什么

如上圖中的 Function10 代表的是:有 10 個形參,返回值為 R(協變)的函數。

函數更常使用的是匿名函數,定義的時候只需要說明輸入參數的類型和函數體即可,不需要名稱如果你要是用的話,一般會把這個匿名函數賦值給一個變量(其實是val常量) 
 表現形式:(傳入參數)=>{方法體}

val f = (name:String)=>println("Hi,"+name)
 f("kafka")

Scala 中的函數其實就是繼承了這些 Trait 的類的對象,如:我們通過函數字面量定義一個函數

Scala 方法和函數的區別是什么

 其實上述函數的定義方式跟如下定義方式等同:

Scala 方法和函數的區別是什么

由于 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 方法和函數的區別是什么

如上,如果我們直接把一個方法賦值給變量會報錯。如果我們指定變量的類型就是函數,那么就可以通過編譯,如下:

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)實際上是進行了兩次方法調用。

Scala 方法和函數的區別是什么

由于 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 方法和函數的區別是什么了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節
推薦閱讀:
  1. Scala的方法和函數
  2. scala

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

庆云县| 靖西县| 云南省| 凌云县| 察雅县| 印江| 宜兰市| 霞浦县| 崇州市| 乌审旗| 麻江县| 安国市| 长垣县| 蕲春县| 于田县| 乌拉特后旗| 洱源县| 曲麻莱县| 鸡泽县| 新民市| 泰安市| 汤阴县| 资溪县| 历史| 辉南县| 深泽县| 盱眙县| 土默特右旗| 麻城市| 林州市| 郑州市| 灵川县| 舒城县| 若羌县| 遵义县| 虹口区| 罗江县| 视频| 义乌市| 延寿县| 罗田县|