hangscer

for推导式

2017/02/11

7.for推导式

7.2 for推导式:内部实现

其实for推导式是个语法糖
比如for{s<-list}或者for{s<-list ch<-s}一层或者二层循环,更或者卫语句、赋值语句等等,最终变为mapforeachwithFilterflatMap等等。

现在给出for语句,之后给出其等价的内部实现。
val states=List("Alabama","Alaska","Virginta","Wyoming")//这是一个list

1
2
3
4
val r=for{
s<-states
}yield s.toUpperCase
states.map(_.toUpperCase)

这个是一层循环,加以字母转换。
解释一下,一一对应关系。
生成器中包含yield表达式,那么该生成器对应一次map操作。第一次生成器表达式决定了最终的结果,如果容器是List,那么结果就是List;如果容器是Vector,那么结果就是Vector
如果定义了多个生成器,会怎么样呢?(多层循环罢了)
多个生成器,除了最后一个外,其他会被转换为flatMap

1
2
3
4
5
6
val r=for{
s<-states
c<-s //其实这里是双层循环 //字符串本事也可被生成器 生成 字符
}yield s"${c}-${c.toUpper}"
states.flatMap(_.toSeq.map(c=>s"$c-${c.toUpper}"))
//结果是List(A-A, l-L, a-A, b-B, a-A, m-M, a-A, A-A, l-L, a-A........)

现在多个卫语句会怎么样呢?

1
2
3
4
5
6
7
val r=for{
s<-states
c<-s //其实这里是双层循环
if c.isUpper //这是一个卫语句
}yield s"${c}-${c.toUpper}"
states.flatMap(_.toStream.withFilter(_.isUpper).map(c=>s"$c-${c.toUpper}")) //使用流很棒啊
//withFilter不会构造输出容器

7.3 for推导式的转化规则

充分认识到像pat<-expr这样的生成器表达式,pat实际上是一个模式表达式(pattern expression)。
让人费解的是:
20170108ProgrammingScala7_1
注释3处x:Int<-list提示type mismatch错误。(x,y)(x,y:String)是可以匹配成功的。(x:Int)模式却mismatch错误。为什么?

pat<-expr
pat<-expr.withFilter{case pat=>true;case _=>false}

Scala在转化for推导式时,要做的第一件事就是将pat<-expr语句转化为pat<-expr.withFilter{case pat=>true;case _=>false}
20170108ProgrammingScala7_2

for(pat<-expr1) yield expr2
expr.map{case pat=>expr2}

如果for推导式中含有一个生成器和一个yield语句,那么转化如上所示。
20170108ProgrammingScala7_3
这个例子里的转化并不是等价的😅😅。

for(pat1<-expr1;pat2<-expr2;...) yield exprN
expr1.flatMap{case pat1=>for(pat2<-expr2 ...) yield exprN}

这里会生成嵌套的for推导式。
20170108ProgrammingScala7_4.png

pat1<-expr1;pat2=expr2 //有点复杂
当生成器之后尾随着值定义时,比较复杂

1
2
3
4
5
6
7
8
//pat1<-expr1;pat2=expr2
(pat1,pat2)<-for{
x1 @ pat1<-expr1
} yield {
val x2 @ pat2=expr2
(x1,x2)
}
//将值定义转化到yield语句中

20170108ProgrammingScala7_5.png