2012-12-29 13 views
6

Quando uso una val in un per-comprensione, ottengo l'avvertimento:Quali sono le regole di visibilità per Vals a Scala per-comprensioni

avvertimento: parola chiave val in per la comprensione è deprecato

nonostante la produzione nell'appendice della sintassi della specifica.

Questo suggerisce che quando faccio qualcosa come

for (x <- xs; a = x) 

Io non sono davvero l'introduzione di una variabile, come ad esempio se faccio qualcosa di simile

for (x <- xs) yield { implicit val a = x; /* more */ } 

dove, come al solito, inizia la brace un nuovo ambito in cui posso introdurre una nuova val, o anche una nuova implicita.

Cosa sto facendo davvero con quello a?

Sto consumando spazio? Mucchio? Qualche altro tipo di alias?

risposta

7

Come una normale definizione di val pat = expr, la cosa alla sinistra del segno di uguale è solo uno schema.

La produzione di Enumerator nella specifica della sintassi mostra che la clausola in un expr può essere un generatore (a <- b), guardia if cond o val def a = b.

Le parti che possono essere espressioni arbitrarie sono b (come indicato a destra di <- e =) e la condizione.

Responder.exec sfrutta il condizionale per eseguire codice arbitrario, valutando banalmente a true.

Ciò significa che si potrebbe fare arbitrari effetti collaterali da un condizionale:

// yucky, yet instructive 
scala> val xs = List(1,2,3) 
scala> def bar(implicit i: Int) = Some(i+1) 
scala> implicit var imp: Int = 0 
scala> for { a<-xs; if { imp=a; true }; b<-bar } yield b 
res6: List[Int] = List(2, 3, 4) 

Allo stesso modo, i desugars def val come segue:

tmp <- xs 
a = f(tmp) // some arbitrary function of tmp 
// amounts to 
(tmp, a) <- for ([email protected] <- xs) yield { val [email protected]=f(tmp); (x, x0) } 

Aspetta, davvero?

scala> def f(vs: List[Int]) = for (a <- vs; b = a+1) yield b 
f: (vs: List[Int])List[Int] 

Avrete bisogno di un recente repl per fare questo:

scala> :javap f 
[snip] 
    public scala.collection.immutable.List<java.lang.Object> f(scala.collection.immutable.List<java.lang.Object>); 
    flags: ACC_PUBLIC 

    Code: 
     stack=3, locals=2, args_size=2 
     0: aload_1  
     1: new   #16     // class $anonfun$f$1 
     4: dup   
     5: invokespecial #17     // Method $anonfun$f$1."<init>":()V 
     8: getstatic  #22     // Field scala/collection/immutable/List$.MODULE$:Lscala/collection/immutable/List$; 
     11: invokevirtual #26     // Method scala/collection/immutable/List$.canBuildFrom:()Lscala/collection/generic/CanBuildFrom; 
     14: invokeinterface #32, 3   // InterfaceMethod scala/collection/TraversableLike.map:(Lscala/Function1;Lscala/collection/generic/CanBuildFrom;)Ljava/lang/Object; 
     19: checkcast  #28     // class scala/collection/TraversableLike 
     22: new   #34     // class $anonfun$f$2 
     25: dup   
     26: invokespecial #35     // Method $anonfun$f$2."<init>":()V 
     29: getstatic  #22     // Field scala/collection/immutable/List$.MODULE$:Lscala/collection/immutable/List$; 
     32: invokevirtual #26     // Method scala/collection/immutable/List$.canBuildFrom:()Lscala/collection/generic/CanBuildFrom; 
     35: invokeinterface #32, 3   // InterfaceMethod scala/collection/TraversableLike.map:(Lscala/Function1;Lscala/collection/generic/CanBuildFrom;)Ljava/lang/Object; 
     40: checkcast  #37     // class scala/collection/immutable/List 
     43: areturn  

vedo due invocazioni di carta, per l'espressione intermedio e per la resa.

Su ulteriore ispezione, il primo anonfun non è un Int => Int (ovvero, a+1) ma uno Int => (Int,Int).

Quindi la val che abbiamo introdotto è stata passata come parte di una tupla.

Problemi correlati