2010-04-11 2 views
7

Что не так, это следующий метод?Использование ленивых оценочных функций в varargs

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

Название официального параметра 'funcs', является очень подозрительным. Параметры имени-имени, реализованные с помощью thunk, не являются явно функциями. –

+0

И это не то, что обычно называют лениво оцененными аргументами. I.e., если вы используете значение несколько раз, выражение, заданное как фактический параметр, оценивается несколько раз. Это имеет последствия для производительности, и если это выражение имеет побочные эффекты, они также будут размножаться. –

+0

Это может быть решение: http://stackoverflow.com/a/34373967/2825964 –

ответ

5

Это на самом деле «работает» под 2.7.7, если добавить скобки:

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

кроме него фактически не работает во время выполнения:

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

В 2.8 он отказывается, чтобы указать X * в качестве выхода любой функции или параметра имени, хотя вы можете указать его как вход (это r21230, пост-бета 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]*) = _ 

Но если вы пытаетесь конвертировать из метода, он работает:

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) 

Так что это не совсем последователен.

В любом случае, возможно, вы можете добиться того, что вы хотите, передавая массив, а затем посылает этот массив к чему-то, что принимает повторяющиеся аргументы:

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 

Если вы действительно хотите (легко) передавать кучу лениво оцениваемых аргументов, тогда вам нужна небольшая инфраструктура, которая, насколько мне известно, не очень хорошо существует в библиотеке (это код для 2.8, рассматривайте ее как вдохновитель для аналогичной стратегии в 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 
} 

Теперь вы можете легко создать кучу параметров которые оцениваются лениво:

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

Очевидно, что повторяющиеся аргументы недоступны для параметров по имени.

+0

Но, просто для ударов, попробуйте следующее: 'def f (oi: Option [Int] *) = oi' в REPL. Интересно, а? –

+0

@Rex_Kerr: Наверное. На что интересное вы имеете дело? –

+1

Вы можете вернуть Option [Int] * из метода, и вы можете использовать (f_), чтобы сделать его функцией. Но попробуйте найти синтаксис, который позволяет вам представлять тип. Поэтому мне непонятно, могут ли повторяющиеся аргументы недоступны для параметров по имени, или синтаксис не позволяет вам выражать нужный тип (или и то, и другое). –

 Смежные вопросы

  • Нет связанных вопросов^_^