Scala理解中val的作用域规则是什么 [英] What are the scoping rules for vals in Scala for-comprehensions

查看:244
本文介绍了Scala理解中val的作用域规则是什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我对理解使用val时,得到警告:

警告:不建议使用val关键字进行理解

尽管在规范的语法附录中进行了说明.

这表明当我做类似的事情

for (x <- xs; a = x)

我并没有真正引入变量,例如,如果我做类似的事情

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

与往常一样,括号在其中开始一个新的作用域,我可以在其中引入新的val甚至是新的隐式.

我真的在做什么a?

我正在消耗堆栈空间吗?堆?还有别的别名吗?

解决方案

像普通的val pat = expr定义一样,等号左侧的内容只是一个模式.

语法规范中的Enumerator生成显示,for-expr中的子句可以是生成器(a <- b),guard if cond或val def a = b.

可以是任意表达式的部分是b(如<-=的右侧所示)和条件.

Responder.exec利用条件来执行任意代码,同时对true进行微不足道的评估.

这意味着您可以根据条件进行任意副作用:

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

类似地,val def desugars如下:

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

真的吗?

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

您需要最近的代表才能这样做:

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       

我看到了map的两个调用,分别是中间表达式和yield.

进一步检查时,第一个匿名提示不是Int => Int(即a+1),而是Int => (Int,Int).

因此,我们引入的val只是作为元组的一部分被传递了.

When I use a val in a for-comprehension, I get the warning:

warning: val keyword in for comprehension is deprecated

despite the production in the syntax appendix of the spec.

This suggests that when I do something like

for (x <- xs; a = x)

I'm not really introducing a variable, such as if I do something like

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

where, as usual, the brace starts a new scope where I can introduce a new val, or even a new implicit.

What am I really doing with that a?

Am I consuming stack space? Heap? Some other kind of alias?

解决方案

Like an ordinary val pat = expr definition, the thing to the left of the equals sign is just a pattern.

The Enumerator production in the syntax spec shows that the clause in a for-expr can be a generator (a <- b), guard if cond or val def a = b.

The parts that can be arbitrary expressions are b (as given to the right of <- and =) and the condition.

Responder.exec takes advantage of the conditional to execute arbitrary code, while evaluating trivially to true.

That means you could do arbitrary side-effects from a conditional:

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

Similarly, the val def desugars as follows:

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

Wait, really?

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

You'll need a recent repl to do this:

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       

I see two invocations of map, for the intermediate expression and for the yield.

On further inspection, the first anonfun is not a Int => Int (i.e., a+1) but a Int => (Int,Int).

So the val we introduced is just getting passed around as part of a tuple.

这篇关于Scala理解中val的作用域规则是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆