Qual è il problema con il seguente metodo?Utilizzo delle funzioni di valutazione lazy in varargs
def someMethod(funcs: => Option[String]*) = {
...
}
Qual è il problema con il seguente metodo?Utilizzo delle funzioni di valutazione lazy in varargs
def someMethod(funcs: => Option[String]*) = {
...
}
Che in realtà "lavora" sotto 2.7.7 se si aggiunge parentesi:
scala> def someMethod(funcs: => (Option[String]*)) = funcs
someMethod: (=> Option[String]*)Option[String]*
tranne che in realtà non funziona in fase di esecuzione:
scala> someMethod(Some("Fish"),None)
scala.MatchError: Some(Fish)
at scala.runtime.ScalaRunTime$.boxArray(ScalaRunTime.scala:136)
at .someMethod(<console>:4)
at .<init>(<console>:6)
at .<clinit>(<console>) ...
In 2.8 si rifiuta di consentire all'utente di specificare X * come l'uscita di ogni funzione o con-nome del parametro, anche se è possibile specificare come un ingresso (questo è r21230, post-Beta 1):
scala> var f: (Option[Int]*) => Int = _
f: (Option[Int]*) => Int = null
scala> var f: (Option[Int]*) => (Option[Int]*) = _
<console>:1: error: no * parameter type allowed here
var f: (Option[Int]*) => (Option[Int]*) = _
Ma se si tenta di convertire da un metodo, funziona:
scala> def m(oi: Option[Int]*) = oi
m: (oi: Option[Int]*)Option[Int]*
scala> var f = (m _)
f: (Option[Int]*) => Option[Int]* = <function1>
scala> f(Some(1),None)
res0: Option[Int]* = WrappedArray(Some(1), None)
quindi non è del tutto coerente.
In ogni caso, si può eventualmente ottenere quello che vuoi, passando in un array e poi l'invio di tale matrice a qualcosa che richiede argomenti ripetuti:
scala> def aMethod(os: Option[String]*) { os.foreach(println) }
aMethod: (os: Option[String]*)Unit
scala> def someMethod(funcs: => Array[Option[String]]) { aMethod(funcs:_*) }
someMethod: (funcs: => Array[Option[String]])Unit
scala> someMethod(Array(Some("Hello"),Some("there"),None))
Some(Hello)
Some(there)
None
Se si vuole veramente (facilmente) passare un mucchio di argomenti calcolati pigramente, quindi avete bisogno di un po 'di infrastruttura che per quanto ne so non esiste nella libreria (questo è il codice per 2.8, vista come ispirazione per una strategia simile in 2.7):
class Lazy[+T](t:() => T, lt: Lazy[T]) {
val params: List[() => T] = (if (lt eq null) Nil else t :: lt.params)
def ~[S >: T](s: => S) = new Lazy[S](s _,this)
}
object Lz extends Lazy[Nothing](null,null) {
implicit def lazy2params[T : Manifest](lz: Lazy[T]) = lz.params.reverse.toArray
}
Ora puoi creare facilmente un gruppo di param Eters che sono ponderati:
scala> import Lz._ // To get implicit def
import Lz._
scala> def lazyAdder(ff: Array[()=>Int]) = {
| println("I'm adding now!");
| (0 /: ff){(n,f) => n+f()}
| }
lazyAdder: (ff: Array[() => Int])Int
scala> def yelp = { println("You evaluated me!"); 5 }
yelp: Int
scala> val a = 3
a: Int = 3
scala> var b = 7
b: Int = 7
scala> lazyAdder(Lz ~ yelp ~ (a+b))
I'm adding now!
You evaluated me!
res0: Int = 15
scala> val plist = Lz ~ yelp ~ (a+b)
plist: Lazy[Int] = [email protected]
scala> b = 1
b: Int = 1
scala> lazyAdder(plist)
I'm adding now!
You evaluated me!
res1: Int = 9
Evidentemente gli argomenti ripetuti non sono disponibili per i parametri di nome.
Ma, solo per i calci, prova questo: 'def f (oi: Option [Int] *) = oi' nella REPL. Interessante, eh? –
@Rex_Kerr: credo. A che cosa ti riferisci? –
È possibile restituire Option [Int] * da un metodo ed è possibile utilizzare (f _) per renderlo una funzione. Ma prova a trovare la sintassi che ti permetta di rappresentare il tipo. Quindi non è chiaro per me se gli argomenti ripetuti non sono disponibili per i parametri di nome, o se la sintassi non ti consente di esprimere il tipo che vuoi (o entrambi). –
Il nome del parametro formale, 'funcs', è altamente sospetto. I parametri By-name, se implementati con un thunk, non sono funzioni apertamente. –
Né sono quelli che vengono comunemente chiamati argomenti calcolati pigramente. Ad esempio, se si utilizza il valore più volte, l'espressione fornita come parametro effettivo viene valutata più volte. Ciò ha conseguenze sulle prestazioni e se quell'espressione ha effetti collaterali, si verificheranno anche moltiplica. –
Questa potrebbe essere una soluzione: http://stackoverflow.com/a/34373967/2825964 –