2010-04-11 15 views
7

Co jest nie tak, to jest następująca metoda?Korzystanie z leniwych funkcji oceny w varargs

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

Nazwa formalnego parametru, 'funcs', jest wysoce podejrzana. Parametry nazwy użytkownika, mimo że realizowane za pomocą thunk, nie są jawnie funkcjami. –

+0

Nie są też tak często określane jako leniwie oceniane argumenty. Oznacza to, że jeśli wartość zostanie użyta wiele razy, wyrażenie podane jako rzeczywisty parametr zostanie ocenione wiele razy. Ma to konsekwencje wydajnościowe i jeśli ta ekspresja wywołuje efekty uboczne, będą one również występować wielokrotnie. –

+0

Może to być rozwiązanie: http://stackoverflow.com/a/34373967/2825964 –

Odpowiedz

5

To rzeczywiście "działa" pod 2.7.7, jeśli dodać parens:

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

poza nim faktycznie nie działa przy starcie:

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

W 2,8 odmawia pozwalają określić X * jako dane wyjściowe dowolnej funkcji lub parametru zastępczego, nawet jeśli można go określić jako dane wejściowe (jest to 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]*) = _ 

Ale jeśli spróbujesz przekonwertować z metodą, to działa:

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) 

Więc nie jest to w pełni zgodne.

W każdym razie, można ewentualnie osiągnąć to, co chcesz przez przechodzącą w tablicy, a następnie wysyłanie tej tablicy do czegoś, co następuje powtarzające się argumenty:

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 

Jeśli naprawdę chcesz (łatwo) przechodzą kilka leniwie ocenianych argumentów, potrzebujesz trochę infrastruktury, która, o ile wiem, niezbyt dobrze istnieje w bibliotece (to jest kod dla 2.8, zobacz jako inspirację dla podobnej strategii w 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 
} 

Teraz możesz łatwo stworzyć garść parametrów etery, które są leniwie oceniane:

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

Ewidentnie powtórzone argumenty nie są dostępne dla parametrów nazwy.

+0

Ale tylko dla kopnięć, spróbuj tego: 'def f (oi: Option [Int] *) = oi' w REPL. Interesujące, co? –

+0

@Rex_Kerr: Chyba. O jakiej interesującej rzeczy się powołujesz? –

+1

Możesz zwrócić opcję [Int] * z metody i możesz użyć (f _), aby była funkcją. Ale spróbuj znaleźć składnię, która pozwala ci reprezentować typ. Więc nie jest dla mnie jasne, czy powtarzające się argumenty nie są dostępne dla parametrów z nazwy, czy też składnia nie pozwala na wyrażenie pożądanego typu (lub obu). –

Powiązane problemy