2015-09-26 15 views
8

Ci sono alcune discussioni qui a riguardo, ma ho alcune domande specifiche per le quali non sono riuscito a trovare una risposta. Quindi, per nome, intendo il tipo =>T e per la funzione 0-arity intendo () => TAlcune domande sulla differenza tra le funzioni call-by-name e 0-arity

Capisco (penso) la differenza concettuale, ma probabilmente mi manca qualcosa perché ho ancora molte domande :

  1. Perché abbiamo il concetto di =>T se potessimo sempre utilizzare () => T?
  2. C'è qualche sintassi/limite funzionale di ciascuno? Per ora ho trovato solo che lo => non può essere usato come un campo di classe. È questa l'unica limitazione?
  3. Il codice generato è sempre lo stesso per entrambi?
  4. Devo sempre preferire =>T? E perché?
  5. È corretto chiamare =>T un tipo? Mi sembra che non abbia alcun tipo di rappresentazione in scala.
+0

Considerate questo commento - https : //twitter.com/StewOConnor/status/633555338894020608 –

risposta

7

1) E 'solo più comodo da usare, DSL soprattutto all'interno:

def printAndGet[T](f: => T) = { 
    val res = f 
    println(res + " printed") 
    res 
} 

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

val k = printAndGet { 
    val a = 5 
    5 * a 
} 

// Exiting paste mode, now interpreting. 

25 printed 
k: Int = 25 

2) => T può essere solo un parametro di metodo o una funzione. E in realtà => T e () => T non sono intercambiabili:

scala> def aaa(f: => String) = f 
aaa: (f: => String)String 

scala> val a: Function1[() => String, String] = aaa _ 
<console>:8: error: type mismatch; 
found : (=> String) => String 
required: (() => String) => String 
     val a: Function1[() => String, String] = aaa _ 
               ^

Grazie a @ som-snytt, fоund questo:

scala> object O { def f(i: Int) = i; def f(i: => Int) = i + 1 } 
defined object O 

scala> O.f(5) 
res12: Int = 5 

scala> O.f(5: (=> Int)) 
<console>:1: error: no by-name parameter type allowed here 
     O.f(5: (=> Int)) 
     ^

Anche questa, che dovrebbe funzionare se si compila - ma non è così (Scala 2.11.2, 2.11.5 REPL si blocca solo):

scala> val k: (=> Int) => Int = O.f _ 
k: (=> Int) => Int = <function1> 

scala> k(5) //should be 6 
res18: Int = 5 //WTF? 

Ultima sembra come un insetto

.210

3) Non esattamente, se si desidera che la stessa, solo convertire => T in () => T:

scala> def aaa(f: => String) = {f _} 
aaa: (f: => String)() => String 

Bytecode può anche essere diverso. Ad esempio, il compilatore sarà più probabile codice inline da => T senza generare lambda per esso. Quindi, la differenza principale è che () => T è in realtà un oggetto (cittadino di prima classe), => T no.

4) vedere 1, ma a volte potrebbe essere necessario assicurarsi che l'utente sappia che il calcolo potrebbe essere ritardato - () => T è meglio allora.

5) E 'parte di una firma tipo, basta guardare eta-espansione:

scala> def aaa(f: => String) = {f} 
aaa: (f: => String)String 

scala> aaa _ //convert method into a function 
res7: (=> String) => String = <function1> 

scala> val a: (=> String) => String = aaa _ 
a: (=> String) => String = <function1> 

Tuttavia Scala non riconosce che tipo di indipendenza:

scala> val a: Function1[(=> String), String] = aaa _ 
<console>:1: error: no by-name parameter type allowed here 
     val a: Function1[(=> String), String] = aaa _ 
         ^
+0

Al n. 2, non è possibile utilizzare l'ascrizione di tipo nome, quindi per sovraccarico 'f (i: Int)' e 'f (i: => Int)' , non puoi 'f (0: => Int)'.Simile al tuo punto sul tipo "indipendente". –

+0

1) Lo capisco. Non capisco perché abbiamo bisogno della notazione speciale '=> T'? Potremmo sempre usare '() => T' e assumere che ogni espressione sia di tipo'() => ', piuttosto che' => T'. – Archeg

+0

2) Questo non sembra vero. Posso almeno usarlo come val locale: 'def aa (f: => String) = {val g = f; println (g)} 'then' aa {println ("elaborato"); "return val"} '. Mi chiedo quale altro uso di esso possa essere – Archeg

Problemi correlati