2012-03-16 9 views
230

私は人為的なアンマーシャリングと動詞の名詞(AddTwoクラスはapplyに2つ追加しました!Scalaのapply関数とは何ですか?

私はそれが構文的な糖であることを理解していますので、(私は文脈から推測しましたが)いくつかのコードをより直感的にするように設計されていなければなりません。

apply機能を持つクラスはどのような意味を持ちますか?どのような目的で使用されていますか、どのような目的でコードが改善されますか(アンマーシャリング、名詞の照合など)?

コンパニオンオブジェクトで使用するとどのように役立ちますか?

+4

すばやいグーグルでも素敵な記事。ここに1つあります:http://jackcoughonsoftware.blogspot.com/2009/01/deeper-look-at-apply-method-in-scala.html –

+0

http://stackoverflow.com/questions/1223834/how-does- scalas-apply-method-magic-work – ses

+4

実際にJava/C++のコンストラクタと同じですが、値を返すことができ、 'apply'という名前を持っています – ses

答えて

508

数学者はそうではなく、「我々はパッシング機能fを呼び出すことxパラメータとして」と言って、自分の少し面白い方法を持って、私たちのプログラマーが言うように、彼らは「その引数xに機能fを適用する」について話します。

数学とコンピュータサイエンスでは、適用は引数に 関数を適用する関数です。
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 

すべてが今Function1[Int,Int]オブジェクトへの参照として扱うことができるスカラf内のオブジェクトであるため。

f.toString 

それとも我々はfcomposeメソッドを呼び出すことによって、別のFunction1[Int,Int]オブジェクトを定義することができます。たとえば、私たちは関数がメソッドを持っていないので、純粋な機能のためには不可能だっただろうAnyから継承されたtoStringメソッドを呼び出すことができます私たちが実際に機能を実行したい場合は今

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

を、または私たちはにapplyメソッドを呼び出すと数学者としての言う「その引数に関数を適用」:2つの異なる機能を一緒に連鎖しますオブジェクト:

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

+0

Scalaの型は、通常、引数に基づいて推論できますが、そうでない場合は、角括弧で指定することができます。したがって、Averageオブジェクトをインスタンス化するときには、「val avg = new Average [Int](0)」と答えることができます –

+3

ケースクラスはここで言及する価値があります。大文字小文字のクラスは便利で、クラスのコンパニオンオブジェクト(他のものの中でも)に 'apply'メソッドと' unapply'メソッドを自動的かつ不可視に追加します。したがって、この 'caseクラスCar(make:String、model:String、year:Short、color:String)のようにただ1行でクラスを定義すると、Carクラスの新しいオブジェクトを生成することができます:' val myCar =カー( "VW"、 "ゴルフ"、1999年、 "ブルー") '。これは 'Car.apply(...)'の省略形です。 –

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) 

多くの場合、クラスのための素敵なファクトリメソッドを提供するために、コンパニオンオブジェクトで使用していますかここでの形質は、一例である:Seqあなたが、これnew Seq(1, 2)はコンパニオンオブジェクトへの感謝が、コンパイルおよび適用されません、形質である:

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(1, 2)と呼び出すことができ、実装は会社によって選択されますイオンオブジェクト。

+0

Implicitsを使用してapplyの同等の処理を行うことはできますか? – jayunit100

3

にハロー出力

グリーター-1メッセージでインスタンス化されて迅速

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") 


} 

グリーター-2を閲覧したい人のための小さな例があることですメッセージワールドでインスタンス化

+0

g2のメッセージは正しいですか?それは実際にインスタンス化で起きているのですか、それともインスタンス化後に(実際にインスタンス化されていても)ですか? –

関連する問題