2012-03-16 73 views
230

我從來沒有從人爲的反編組和名詞性名詞中理解它(AddTwo類有apply,增加了兩個!)例子。Scala中的應用函數是什麼?

我知道它是語法糖,所以(我從上下文中推導出來)它的設計必須讓代碼更加直觀。

apply函數給類的含義是什麼?它用於什麼目的,它爲什麼使代碼更好(解組,名詞等)?

它在協同對象中使用時有什麼幫助?

+4

即使是一個快速的谷歌搜索帶來了很多好文章。這裏是一個:http://jackcoughonsoftware.blogspot.com/2009/01/deeper-look-at-apply-method-in-scala.html – 2012-03-16 12:46:13

+0

http://stackoverflow.com/questions/1223834/how-does- scalas-apply-method-magic-work – ses 2012-12-16 22:01:33

+4

實際上它與Java/C++中的構造函數相同,但可以返回值並具有「應用」名稱 – ses 2012-12-16 22:29:08

回答

508

數學家都有自己的小滑稽的方式,所以不是說「則稱函數f傳遞x作爲參數」,因爲我們的程序員會說,他們談論「賦予功能f其說法x」。

在數學和計算機科學,應用是適用 函數參數的函數。
Wikipedia

apply供應閉面向對象與功能範例之間的間隙Scala中的目的。 Scala中的每個函數都可以表示爲一個對象。每個函數也有一個OO類型:例如,一個參數爲Int且返回Int的函數將具有OO類型Function1[Int,Int]

// define a function in scala 
(x:Int) => x + 1 

// assign an object representing the function to a variable 
val f = (x:Int) => x + 1 

由於一切是Scala f一個目的現在可以以Function1[Int,Int]對象的引用被處理。例如,我們可以調用toString方法從Any繼承,那將是不可能的純函數,因爲函數沒有方法:

f.toString 

或者,我們可以通過調用fcompose方法定義另一個Function1[Int,Int]對象和鏈接兩個不同的功能結合在一起:

val f2 = f.compose((x:Int) => x - 1) 

現在,如果我們要實際執行的功能,或者作爲數學家說:「應用功能,它的參數:」我們將調用apply方法對Function1[Int,Int]對象:

f2.apply(2) 

要執行代表爲對象的功能,每次寫f.apply(args)是面向對象的方式,但會增加很多雜亂的代碼無需增加多少額外的信息,這將是很高興能夠使用更多的標準符號,如f(args)。這就是Scala編譯器的步驟,當我們有一個參考f函數對象和編寫f (args)將參數應用於表示函數編譯器無聲地擴展f (args)對象方法調用f.apply (args)

Scala中的每個函數可以被視爲一個對象,它的工作原理其他方式太 - 每個對象都可以作爲一個函數來處理,只要它有apply方法。這樣的對象可以在函數符號可以使用:

// we will be able to use this object as a function, as well as an object 
object Foo { 
    var y = 5 
    def apply (x: Int) = x + y 
} 


Foo (1) // using Foo object in function notation 

有很多使用情況下,當我們要正確對待一個對象作爲一個功能。最常見的情況是factory pattern。而不是使用一個工廠方法,我們可以apply對象的一組參數來創建一個關聯類的一個新實例添加雜波代碼:

List(1,2,3) // same as List.apply(1,2,3) but less clutter, functional notation 

// the way the factory method invocation would have looked 
// in other languages with OO notation - needless clutter 
List.instanceOf(1,2,3) 

所以apply方法是關閉之間的差距只是一種方便的方法在Scala中的函數和對象。

+1

如何將自定義變量類型添加到對象。 AFAIK這是不可能的。這裏是一個例子:你有這個類'class Average [YType](yZeroValue:YType)'。你如何從它的對象傳遞YType,因爲對象不能使用類型參數? – Adrian 2014-02-26 15:24:01

+0

Scala中的類型通常可以根據參數進行推斷,但如果不是,則可以通過方括號提供它們。所以當實例化一個Average對象時,可以說「val avg = new Average [Int](0)」 – 2014-07-06 19:26:14

+3

案例類在這裏值得一提。案例類方便,自動和無形地將'apply'和'unapply'方法添加到類的伴侶對象中(等等)。因此,使用'case class Car(make:String,model:String,year:Short,color:String)'這樣的一行來定義類就可以通過以下方法生成Car類的新對象:'val myCar =汽車( 「大衆」, 「高爾夫」,1999年, 「藍」)'。這是'Car.apply(...)'的簡寫' – 2017-09-27 09:10:55

37

它來自這樣的想法,你經常想應用東西到一個對象。更準確的例子是工廠之一。當你有工廠時,你想要應用參數來創建一個對象。

斯卡拉人認爲,因爲它發生在許多情況下,它可能是一個快捷方式撥打apply。因此,當你給直接參數到一個對象,它是因爲如果你把這些參數傳遞給該對象的應用功能脫:

class MyAdder(x: Int) { 
    def apply(y: Int) = x + y 
} 

val adder = new MyAdder(2) 
val result = adder(4) // equivalent to x.apply(4) 

它經常在同伴的對象使用,提供了一類一個不錯的工廠方法或一個特點,這裏有一個例子:

trait A { 
    val x: Int 
    def myComplexStrategy: Int 
} 

object A { 
    def apply(x: Int): A = new MyA(x) 

    private class MyA(val x: Int) extends A { 
    val myComplexStrategy = 42 
    } 
} 

從Scala的標準庫,你可能看scala.collection.Seq是如何實現的:Seq是一個特點,從而new Seq(1, 2)不會編譯,但由於同伴對象和應用,你可以撥打電話Seq(1, 2),由公司選擇實施離子對象。

+0

使用Implicits也可以實現等價的應用嗎? – jayunit100 2014-08-15 02:13:17

3

這裏是誰想要細讀的小例子迅速

object ApplyExample01 extends App { 


    class Greeter1(var message: String) { 
    println("A greeter-1 is being instantiated with message " + message) 


    } 

    class Greeter2 { 


    def apply(message: String) = { 
     println("A greeter-2 is being instantiated with message " + message) 
    } 
    } 

    val g1: Greeter1 = new Greeter1("hello") 
    val g2: Greeter2 = new Greeter2() 

    g2("world") 


} 

輸出

甲招待員-1被實例化消息hello

甲招待員-2被與消息世界實例化

+0

g2的消息是否正確?這實際上是在實例化中發生,還是事實上在實例化之後(即使它是懶惰實例化的)? – 2018-01-02 15:25:22

相關問題