Scalaの適用機能とは何ですか?


311

不自然な動詞化された名詞(AddTwoクラスにはapply2つ追加された!)の例から、私はそれを理解できませんでした。

私はそれが構文上の砂糖であることを理解しているので、(私はコンテキストから推測して)いくつかのコードをより直観的にするように設計されていたに違いありません。

apply関数を持つクラスはどのような意味を持ちますか?それは何のために使用され、コードを改善する目的は何ですか(非整列化、動詞の名詞など)?

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


4
すばやくグーグルしても、たくさんの素晴らしい記事がもたらされます。:ここでは一つですjackcoughonsoftware.blogspot.com/2009/01/...
OM-NOM-NOMは、


6
実際には、Java / C ++のコンストラクターと同じですが、値を返すことができ、名前を「適用」できます
ses

関数ではなくメソッドです。メソッドと関数の違いは、Scalaでは非常に重要です。
15

1
Zoidbergについて詳しく説明するには、「メソッドは、クラスの状態にアクセスすることができますだけで機能している」twitter.github.io/scala_school/basics.htmlこれはよりスカラ座よりに適用される一般的にstackoverflow.com/questions/155609/...は
DharmaTurtle

回答:


641

数学者は独自の少し面白い方法を持っているので、プログラマーが言うように「それをパラメーターとしてf渡して関数を呼び出す」と言う代わりに、「引数にx関数fを適用する」と話しますx

数学とコンピュータサイエンスでは、Applyは引数に関数を適用する関数です。
ウィキペディア

applyScalaのオブジェクト指向パラダイムと機能パラダイムの間のギャップを埋める目的を果たします。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

または、メソッドをFunction1[Int,Int]呼び出して2つの異なる関数をチェーンすることで、別のオブジェクトを定義することもできます 。composef

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

関数を実際に実行する場合、または数学者が「関数を引数に適用する」と言う場合はapplyFunction1[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 

オブジェクトを関数として扱いたい場合、多くの使用例があります。最も一般的なシナリオは、ファクトリパターンです。ファクトリメソッドを使用してコードに混乱を追加する代わり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
オブジェクトにカスタム変数タイプをどのように追加しますか。私の知る限り、それは不可能です。次に例を示しますclass Average[YType](yZeroValue:YType)。このクラスがあります。オブジェクトはタイプパラメータを取得できないため、そのオブジェクトからYTypeをどのように渡しますか?
エイドリアン

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

4
ケースクラスはここで言及する価値があります。Caseクラスは、クラスのコンパニオンオブジェクトに(特に)、便利で、自動的かつ不可視に追加applyおよびunapplyメソッドします。したがって、このように1行だけでクラスを定義するcase class Car(make:String, model: String, year: Short, color: String)と、Carクラスの新しいオブジェクトを次のように作成できますval myCar = Car("VW","Golf",1999,"Blue")。これは省略形ですCar.apply(...)
Kjetil S.

1
every object can be treated as a function, provided it has the apply method-今はとても理にかなっています。
Arj


51

それは、オブジェクトに何かを適用したいことがよくあるという考えから来ています。より正確な例は、工場の1つです。ファクトリーがある場合、それにパラメーターを適用してオブジェクトを作成します。

Scalaの人たちは、さまざまな状況で発生するため、を呼び出すショートカットを用意しておくと便利だと考えていましたapply。したがって、オブジェクトにパラメータを直接指定すると、これらのパラメータをそのオブジェクトの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)、コンパニオンオブジェクトによって実装が選択されます。


適用と同等のものは、暗黙的にも実現できますか?
jayunit100 2014

11

これはすぐに熟読したい人のための小さな例です

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


} 

出力

greeter-1はメッセージhelloでインスタンス化されています

greeter-2がメッセージの世界でインスタンス化されています


2
g2のメッセージは正しいですか?それは実際にインスタンス化時に発生していますか、それとも実際にはインスタンス化の後に発生しますか(遅延インスタンス化されている場合でも)?
Tim Barrass、2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.