2010-04-11 12 views
7

¿Qué problema hay con el siguiente método?Uso de las funciones de evaluación diferidas en varargs

def someMethod(funcs: => Option[String]*) = { 
... 
} 
+0

El nombre del parámetro formal, 'funcs', es muy sospechoso. Los parámetros By-name, si bien se implementan con un thunk, no son funciones manifiestamente. –

+0

Tampoco son lo que comúnmente se conoce como argumentos evaluados perezosamente. Es decir, si usa el valor varias veces, la expresión dada como el parámetro real se evalúa varias veces. Eso tiene consecuencias en el rendimiento y si esa expresión tiene efectos secundarios, también se multiplicarán. –

+0

Esa puede ser una solución: http://stackoverflow.com/a/34373967/2825964 –

Respuesta

5

Que en realidad "trabaja" en 2.7.7 si se agrega parens:

scala> def someMethod(funcs: => (Option[String]*)) = funcs 
someMethod: (=> Option[String]*)Option[String]* 

excepto que en realidad no trabajar en tiempo de ejecución:

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

En 2.8 se niega a permitir que se especifiquen X * como salida de cualquier función o parámetro de nombre, aunque puede especificarlo como entrada (esto es r21230, posterior a la versión 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]*) = _ 

Pero si intenta convertir de un método, funciona:

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) 

así que no es del todo coherente.

En cualquier caso, puede posiblemente lograr lo que desea pasando de una matriz y luego enviar esa matriz a algo que toma argumentos repetidos:

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 

Si realmente desea pasar (fácilmente) un manojo de argumentos evaluados perezosamente, entonces necesita un poco de infraestructura que, por lo que sé, no existe muy bien en la biblioteca (esto es código para 2.8; véalo como inspiración para una estrategia similar en 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 
} 

Ahora puedes crear fácilmente un grupo de param eters que se evalúan de forma diferida:

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 
3

Los argumentos evidentemente repetidos no están disponibles para los parámetros de nombre por nombre.

+0

Pero, solo por las patadas, intente esto: 'def f (oi: Option [Int] *) = oi' en REPL. Interesante, ¿eh? –

+0

@Rex_Kerr: supongo. ¿A qué cosa interesante te estás refiriendo? –

+1

Puede devolver la Opción [Int] * desde un método, y puede usar (f _) para que sea una función. Pero intente encontrar la sintaxis que le permita representar el tipo. Por lo tanto, no está claro si los argumentos repetidos no están disponibles para los parámetros de nombre o si la sintaxis no le permite expresar el tipo que desea (o ambos). –

Cuestiones relacionadas