Scala'da uygula işlevi nedir?


311

Bunu hiç de anlaşılmaz ve sözsüz isimlerden anlayamadım (bir AddTwosınıfın applyiki tane ekleyen bir örneği var!).

Sözdizimsel şeker olduğunu anlıyorum, bu yüzden (bağlamdan çıkarıldım) bazı kodları daha sezgisel hale getirmek için tasarlanmış olmalı.

applyFonksiyonu olan bir sınıfın anlamı nedir ? Ne için kullanılır ve kodu hangi amaçlar için daha iyi hale getirir (utanmaz, sözlü isimler vb.)?

Tamamlayıcı bir nesnede kullanıldığında nasıl yardımcı olur?


4
Hızlı bir googling bile birçok güzel makale getiriyor. İşte bir tanesi: jackcoughonsoftware.blogspot.com/2009/01/…
om-nom-nom


6
aslında Java / C ++ 'da bir kurucu ile aynıdır ancak değeri döndürebilir ve' uygula 'adına sahiptir
ses

Bir yöntem değil, bir yöntem. Scala'da yöntemler ve fonksiyonlar arasındaki ayrım çok önemlidir.
sağ kanat

1
Zoidberg hakkında ayrıntılı bilgi için, "Yöntemler yalnızca sınıfın durumuna erişebilen işlevlerdir" twitter.github.io/scala_school/basics.html Genel olarak bu Scala'dan daha fazlası için geçerlidir stackoverflow.com/questions/155609/…
DharmaTurtle

Yanıtlar:


641

Matematikçilerin kendi küçük komik yolları vardır, bu yüzden programcıların dediği gibi "o zaman fonu xparametre olarak geçirmeyi fonksiyon olarak adlandırıyoruz " demek yerine " fargümana fonksiyon uygulama" hakkında konuşurlar x.

Matematik ve bilgisayar biliminde, Uygula argümanlara fonksiyonlar uygulayan bir fonksiyondur.
Vikipedi

applyScala'da Nesneye Yönelik ve Fonksiyonel paradigmalar arasındaki boşluğu kapatma amacına hizmet eder. Scala'daki her fonksiyon bir nesne olarak temsil edilebilir. Her işlevin ayrıca bir OO türü vardır: örneğin, bir Intparametre alan ve bir döndüren işlev IntOO türüne sahip olacaktır 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'da her şey bir nesne olduğundan f, şimdi Function1[Int,Int]nesneye referans olarak değerlendirilebilir . Örneğin, toStringdevralınan Any, saf bir işlev için imkansız olan yöntemi çağırabiliriz , çünkü işlevlerin yöntemleri yoktur:

  f.toString

Veya yöntemi Function1[Int,Int]çağırıp iki farklı işlevi bir araya getirerek başka bir nesne tanımlayabiliriz :composef

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

Şimdi işlevi gerçekten yürütmek istiyorsak veya matematikçinin "argümanlarına bir işlev uygula" dediği gibi apply, Function1[Int,Int]nesneyi yöntemi çağırırız :

 f2.apply(2)

f.apply(args)Nesne olarak temsil edilen bir işlevi her yürütmek istediğinizde yazmak Nesneye Dayalı yoldur, ancak çok fazla ek bilgi eklemeden koda çok fazla dağınıklık ekler ve daha standart gösterimi kullanmak güzel olurdu, örneğin olarak f(args). Scala derleyicisinin devreye girdiği yer burasıdır ve fbir işlev nesnesine f (args)başvurumuz olduğunda ve temsil edilen işleve bağımsız değişkenler uygulamak için yazdığımızda derleyici f (args), nesne yöntemi çağrısına sessizce genişler f.apply (args).

Scala'daki her işlev bir nesne olarak ele alınabilir ve başka şekilde de çalışır - applyyönteme sahip olması koşuluyla, her nesne bir işlev olarak ele alınabilir . Bu tür nesneler fonksiyon gösterimlerinde kullanılabilir:

// 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 

Bir nesneyi işlev olarak ele almak istediğimiz birçok kullanım durumu vardır. En yaygın senaryo bir fabrika modelidir . Bir fabrika yöntemini kullanarak koda karmaşa eklemek yerine, applyilişkili bir sınıfın yeni bir örneğini oluşturmak için bir dizi bağımsız değişkene itiraz edebiliriz :

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) 

Bu nedenle applyyöntem, Scala'daki işlevler ve nesneler arasındaki boşluğu kapatmanın kullanışlı bir yoludur.


1
bir nesneye nasıl özel değişken türü eklersiniz. AFAIK mümkün değil. İşte bir örnek: Bu sınıfa sahipsiniz class Average[YType](yZeroValue:YType). Nesneler yazım parametrelerini alamadığından YType'ı nesnesinden nasıl geçirirsiniz?
Adrian

Scala'daki türler genellikle bağımsız değişkenlere dayanarak çıkarılabilir, ancak değilse köşeli parantezler aracılığıyla bunları sağlayabilirsiniz. Ortalama bir nesneyi başlatırken "val avg = new Average [Int] (0)" diyebilirsiniz
Angelo Genovese

4
Vaka sınıfları burada değinmeye değer. Vaka sınıfları , sınıfın tamamlayıcı nesnesine (diğer şeylerin yanı sıra) uygun, otomatik ve görünmez bir şekilde ekler applyve unapplyyöntemler ekler . Böyle bir tek doğru bir sınıfı tanımlarken Yani case class Car(make:String, model: String, year: Short, color: String)mümkün sadece tarafından Araba sınıfının yeni nesneler üretmek için yapar: val myCar = Car("VW","Golf",1999,"Blue"). Bu kestirme içinCar.apply(...)
Kjetil S.

1
every object can be treated as a function, provided it has the apply method- şimdi çok mantıklı.
Arj


51

Bir nesneye sıklıkla bir şey uygulamak istediğiniz fikrinden gelir . Daha doğru örnek fabrikalardan biridir. Bir fabrikanız olduğunda, bir nesne oluşturmak için ona parametre uygulamak istersiniz .

Scala adamları, birçok durumda olduğu gibi, aramak için bir kısayola sahip olmanın güzel olabileceğini düşündüler apply. Bu nedenle, parametreleri doğrudan bir nesneye verdiğinizde, bu parametreleri o nesnenin uygula işlevine geçirirsiniz.

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

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

Bir sınıf veya özellik için güzel bir fabrika yöntemi sağlamak için genellikle tamamlayıcı nesnede kullanılır, işte bir örnek:

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 standart kitaplığından, nasıl scala.collection.Sequygulandığına bakabilirsiniz : Seqbir özelliktir, bu nedenle new Seq(1, 2)derlenmez, ancak tamamlayıcı nesne ve uygulama sayesinde arayabilir Seq(1, 2)ve uygulama tamamlayıcı nesne tarafından seçilir.


Uygulamanın eşdeğeri Implicits kullanılarak da gerçekleştirilebilir mi?
jayunit100

11

İşte hızlı bir şekilde incelemek isteyenler için küçük bir örnek

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


} 

çıktı

Bir merhaba-1 mesajı merhaba ile başlatılıyor

Bir selamlama-2 mesaj dünyasıyla somutlaştırılıyor


2
G2 mesajı doğru mu? Bu aslında örneklemede mi oluyor, yoksa gerçekte örneklemeden sonra mı (tembel bir şekilde başlatılmış olsa bile)?
Tim Barrass
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.