为什么两个 Some[Int] 可以在 for/yield 表达式中求和?
Why can two Some[Int] sum up in for/yield expression?
val listSomeInt: List[Some[Int]] = List(Some(1),Some(2))
// Some(1) + Some(2) will not compile of course
问题一:为什么同样的和计算在for/yield表达式中有效?
val sumSomeInt = for{
i1<- listSomeInt(0)
i2<- listSomeInt(1)
} yield i1 + i2
println(sumSomeInt) // Some(3)
问题 2:如何通过 println(i1.getClass) 或其他方式查看 "for{}" 中 i1 的类型?
反编译可能会给出一些提示,但不是那么彻底(对我而言)。
private final List<Some<Object>> listSomeInt = …;
public List<Some<Object>> listSomeInt() { return this.listSomeInt; }
public Option<Object> sumSomeInt() { return this.sumSomeInt; }
private final Option<Object> sumSomeInt = (Option)listSomeInt().apply(0)).flatMap(this::$anonfun$sumSomeInt$adapted);
这个:
for{
i1<- listSomeInt(0)
i2<- listSomeInt(1)
} yield i1 + i2
是语法糖:
listSomeInt(0).flatMap { i1 =>
listSomeInt(1).map { i2 =>
i1 + i2
}
}
等于:
Option(1).flatMap { i1 =>
Option(2).map { i2 =>
i1 + i2
}
}
您可以进一步解释为:
Option(1).map { i1: Int => // i1 == 1 in this example
Option(2).map { i2: Int => // i2 == 2 in this example
i1 + i2 // i1 + i2 == 3 in this example
} // Option[Int] == Some(3)
} // Option[Option[Int]] == Some(Some(3))
.flatten // Option[Int] == Some(3)
如果您使用像菊石这样的 REPL 来测试部分结果,您可以预览其中的许多内容:
@ Option(1).map(i => i *2)
res9: Option[Int] = Some(2)
@ Option(1).map(i => Option(i * 2))
res10: Option[Option[Int]] = Some(Some(2))
@ Option(1).map(i => Option(i * 2)).flatten
res11: Option[Int] = Some(2)
@ Option(1).flatMap(i => Option(i * 2))
res12: Option[Int] = Some(2)
@ Option(1).map(i => Option(2).map(j => i + j)).flatten
res13: Option[Int] = Some(3)
@ Option(1).flatMap(i => Option(2).map(j => i + j))
res14: Option[Int] = Some(3)
很好 IDE(例如 IntelliJ)也能够将类型添加到代码中。
for-comprehension只是flatMap、map、filter的语法糖,你的代码相当于:
val option1 = Some(1)
val option2 = Some(2)
val sumOptions = option1.flatMap { i =>
option2.map { j =>
i + j
}
}
val listSomeInt: List[Some[Int]] = List(Some(1),Some(2))
// Some(1) + Some(2) will not compile of course
问题一:为什么同样的和计算在for/yield表达式中有效?
val sumSomeInt = for{
i1<- listSomeInt(0)
i2<- listSomeInt(1)
} yield i1 + i2
println(sumSomeInt) // Some(3)
问题 2:如何通过 println(i1.getClass) 或其他方式查看 "for{}" 中 i1 的类型?
反编译可能会给出一些提示,但不是那么彻底(对我而言)。
private final List<Some<Object>> listSomeInt = …;
public List<Some<Object>> listSomeInt() { return this.listSomeInt; }
public Option<Object> sumSomeInt() { return this.sumSomeInt; }
private final Option<Object> sumSomeInt = (Option)listSomeInt().apply(0)).flatMap(this::$anonfun$sumSomeInt$adapted);
这个:
for{
i1<- listSomeInt(0)
i2<- listSomeInt(1)
} yield i1 + i2
是语法糖:
listSomeInt(0).flatMap { i1 =>
listSomeInt(1).map { i2 =>
i1 + i2
}
}
等于:
Option(1).flatMap { i1 =>
Option(2).map { i2 =>
i1 + i2
}
}
您可以进一步解释为:
Option(1).map { i1: Int => // i1 == 1 in this example
Option(2).map { i2: Int => // i2 == 2 in this example
i1 + i2 // i1 + i2 == 3 in this example
} // Option[Int] == Some(3)
} // Option[Option[Int]] == Some(Some(3))
.flatten // Option[Int] == Some(3)
如果您使用像菊石这样的 REPL 来测试部分结果,您可以预览其中的许多内容:
@ Option(1).map(i => i *2)
res9: Option[Int] = Some(2)
@ Option(1).map(i => Option(i * 2))
res10: Option[Option[Int]] = Some(Some(2))
@ Option(1).map(i => Option(i * 2)).flatten
res11: Option[Int] = Some(2)
@ Option(1).flatMap(i => Option(i * 2))
res12: Option[Int] = Some(2)
@ Option(1).map(i => Option(2).map(j => i + j)).flatten
res13: Option[Int] = Some(3)
@ Option(1).flatMap(i => Option(2).map(j => i + j))
res14: Option[Int] = Some(3)
很好 IDE(例如 IntelliJ)也能够将类型添加到代码中。
for-comprehension只是flatMap、map、filter的语法糖,你的代码相当于:
val option1 = Some(1)
val option2 = Some(2)
val sumOptions = option1.flatMap { i =>
option2.map { j =>
i + j
}
}