Tamam, işte tam bir bozulma.
def value: Int = ???
def method(): Int = ???
def f1(f:() => Int) = ???
def f2(f: => Int) = ???
f1(value) // fails
f1(method) // works
f2(value) // works
f2(method) // works with a warning "empty-paren method accessed as parameterless"
-
f1 (değer)
f1
=> Int fonksiyonu bir birim bekliyor, ancak Int değeri verilir, çünkü bu, bir başarısız olur.
-
f1 (yöntem)
Bu seferki f1
bir işlev bekliyor çünkü çalışır ve bir yöntem verilmiştir. İşte fark: Yöntem Scala'da bir değer değil; Kendi başına var olamaz ve tanımladığı bağlamın bir özniteliğidir (sınıf, özellik, nesne vb.). İşlev bir değerdir; Başka bir işlevde argüman olarak alınan, bir işlevden döndürülen bir koleksiyonda saklanabilir. Derleyici bir işlev beklediğinde ve bir yöntem verildiğinde, eta genişletme gerçekleştirir. Bir fonksiyon verildi, örn. f: (a: Int, b: Int) => Int
, eta genişlemesi, imzayı korurken bir başka tabakanın yaratılması sürecidir, dolayısıyla (a: Int, b: Int) => f(a, b)
olur. Bu teknik yararlıdır çünkü yöntemleri işe dönüştürebiliriz. Bazı yöntem def f(a: Int): Int = ???
göz önüne alındığında, Int => Int dışında bir işlev oluşturmak için eta-genişletme gerçekleştirebiliriz: (a: Int) => f(a)
. İlgilendiğiniz bir süre önce bu konuda blog post yazdım.
-
f2 (değer) sürprizler olmadan
İşleri fakat geçirilen değeri de kullanıldığı her zaman erişilir gerçeğine dikkat işlev gövdesi.
-
f2 (yöntem)
Works, ancak kullanarak boş parantez ile tanımlanır biz yöntemini çağırıyoruz bir uyarı ile hiçbir parantez. İyi bir uygulama da sadece bir değeri temsil parantez (örneğin f
) olmadan yöntemleri kullanmak, ama erişilir her örneğin hesaplanır bir numberOfUpvotes
sayılı patent neşriyatı ve bir çeşit yan etki gerçekleştirildiğinde ve dolayısıyla yöntem idempotent olmadığında, örneğin, boş parantezli (örneğin, f()
) yöntemleri kullanmak için; createSnapshot()
(yine, bu sadece işlevsel kodda bulunmamalıdır).
Tavsiyede bulunun: neyin ne ile değiştirildiğini zihnine kaptırma. Değiştirmeleri kullanmayın. Bir şeyin bir fonksiyona ihtiyacı varsa, ona bir işlev verin. Bir değere ihtiyacı varsa, bir değer belirtin. Bir yöntem, parens olmadan tanımlanırsa, parensiz olarak çağırır. Parens varsa, onu parens ile çağır.
Yöntemden işleve gitmeniz gerekiyorsa ve derleyici bir işlev beklediyse, eta genişletme otomatik olarak gerçekleşir. Bir işlev beklemiyorsa, bunu manuel olarak yapmanız gerekir.
def f(): Int = ???
val a = f // no function context; a is a string
val b:() => Int = f // b is a function Unit => Int
val c = f2 _ // c is a function Unit => Int
Son durum kısmen uygulanan bir işlevdir. Şimdi çok geniş gidiyorum gibi hissediyorum, bu yüzden burada duracağım. Umarım bu yardımcı oldu.
Örnekleriniz kesinlikle * değil * eşdeğerdir. Birincisi, bir deneyin [() ⇒ Int] 'i, ikincisi ise' [Int] 'ı üretir. tip '() elinde işlev argümanı Int'' 't 'olmak t' ⇒ dönüştürülür alır ⇒'() Int' ⇒. –
Burada bazı iyi bilgiler: https://tpolecat.github.io/2014/06/26/call-by-name.html – nevets1219
Bunlar birbirinin yerine geçmez ve Scala derleyici tarafından birbirlerine dönüştürülmezler. Onlar sadece farklı şeylerdir ve genellikle farklı amaçlara hizmet ederler. Jean-PhilippePellet noktaya @ –