2017-09-12 35 views
5

=> T ve Function0 parametreleri () => T parametrelerinin Scala derleyici tarafından birbirine nasıl dönüştürüldüğüne dair kesin bir cevap verebilir mi? Onların aynı olmadıklarını biliyorum, ancak fark çoğu senaryoda birbirinin yerine kullanılabileceği için çok ince.Scala: Function0 ve by-name parametreleri

Örnek:

def someFunction: Int = 2 
def f(x: => Int): Unit = println(x) 

tanımlar o zaman başarıyla

f(2) 
f(someFunction) 

nasıl () => Int=> Int için kabul edilebilir bir yerine geçer arayabilir?

Daha genel olarak, => T bir by-name için evrensel olarak kabul edilebilir bir değiştirmedir? Önce bir değer tipi (T) olduğu için => T() => T için kabul edilebilir bir yedek asla başka bir işlev türüdür: Ben şu akıl yürütmeye yanılıyorsam Ayrıca

, beni düzeltin lütfen. Yani, def f(x:() => Int) varsa, hiçbir zaman Int veya tembel bir Int'u geçemeyeceğim (tembel türler olmadığından bile mantıklı değil).

+5

Ö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' ⇒. –

+0

Burada bazı iyi bilgiler: https://tpolecat.github.io/2014/06/26/call-by-name.html – nevets1219

+0

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 @ –

cevap

3

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" 
  1. f1 (değer)

f1 => Int fonksiyonu bir birim bekliyor, ancak Int değeri verilir, çünkü bu, bir başarısız olur.

  1. 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.

  1. 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.

  1. 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.