for表达式的背后

转载自:http://hongjiang.info/scala-pitfalls-3/

了解一下for表达式转换的细节:
for((key,value) <- m; name=key) {
    println(name)
}
这里有一个map,里面有一些自定义类型的数据,然后在用上面的for进行操作,运行时会发现上面的代码时发现key的hashCode会被调用。而使用下面的写法则没有问题:
for((key,value) <- m) {
    val name=key
    println(name)
}

Why?
       for表达式可以这样描述:
for([pattern <- generator; definition*]+; filter* )
    [yield] expression
       在for小括号(也可以用花括号)内部由一个或多个 p <- generator; definition* 以及0个或多个filter组成。后跟着一个可选的yield关键字,以及后续的逻辑表达。
       把 p <- generator; definition* 这句再展开,由一个 p <- generator 以及0个或多个definition组成。
       这个问题的细节就在于有没有definition对for表达式在转换时的影响;也就是说 for(p <- generator) 与 for(p <- generator; definition) 是不一样的。
       没有yield关键字,for((key,value) <- m) 直接翻译为:
m.foreach(…)
       而 for((key,value) <- m; name=key) 被翻译为:
m.map(…).foreach(…)
       为什么中间多了一次map操作?通过一个简单例子来看:
scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> val list = List("A","B","C")
list: List[String] = List(A, B, C)

scala> reify( for(e <- list; x=e;y=e) { println(x+y) } )
res5: reflect.runtime.universe.Expr[Unit] =
Expr[Unit]($read.list.map(((e) => {
  val x = e;
  val y = e;
  Tuple3.apply(e, x, y)
}))(List.canBuildFrom).foreach(((x$1) => x$1: @unchecked match {
  case Tuple3((e @ _), (x @ _), (y @ _)) => Predef.println(x.$plus(y))
})))
}))(List.canBuildFrom).foreach(((x$1) => x$1: @unchecked match {
    case Tuple3((e @ _), (x @ _), (y @ _)) => Predef.println(x.$plus(y))
})))
       从reify的结果可以看到,对于for(e <- list; x=e; y=e) 里面的x=e和y=e两个definition中的变量x,y与e一同用一个tuple封装起来,即map的结果得到的是一个 List[Tuple3] 类型的数据。随后再对这个新结果进行foreach。
       所以最初的问题是因为for里面存着了一个definition,而导致转换过程多了一次map,也就是创建了一个新的Map[Tuple2],并把数据放入新Map,在这个过程导致了hashCode的调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值