理解产量会导致类型不匹配的编译器错误
我想从Iterable[Try[Int]]
中提取所有有效值(Iterable[Int]
)的列表
I want to extract from Iterable[Try[Int]]
a list of all valid values (Iterable[Int]
)
val test = List(
Try(8),
Try(throw new RuntimeException("foo")),
Try(42),
Try(throw new RuntimeException("bar"))
)
以下是从test
打印所有有效值的方法:
The following is the way to print all valid values from test
:
for {
n <- test
p <- n
} println(p)
// Output
// 8
// 42
但是,当我尝试将有效值保存到列表中时,出现了错误:
However, when I tried to save the valid values to list I have received an error:
val nums: Seq[Int] = for {
n <- list
p <- n // Type mismatch. Required: IterableOnce[Int], found Try[Int]
} yield(p)
println(nums)
如何解决该错误以及为何引发该错误?
How to fix the error and why it was raised?
尝试收集
test.collect { case Success(value) => value }
// res0: List[Int] = List(8, 42)
采用对应的理解格式
for { Success(p) <- test } yield p
两者都使用构造函数在引擎盖下执行isInstanceOf
型式测试并随后进行asInstanceOf
型式转换的图案.也许对应于类似
Both make use of Constructor Patterns which under the hood perform isInstanceOf
type test followed by asInstanceOf
type cast. Verbosly that corresponds to something like
test
.filter (_.isInstanceOf[Success[Int]])
.map (_.asInstanceOf[Success[Int]].value)
下面的理解不起作用,因为其中的单子必须对齐
The following for-comprehension does not work because the monads in it have to align
for {
n <- test // List monad
p <- n // does not align with Try monad
} yield (p)
上述理解的解决方法
test.flatMap((n: Try[Int]) => n.map((p: Int) => p))
并查看flatMap
的签名,我们看到它期望一个功能
and looking at the signature of flatMap
we see it expects a function
Try[Int] => IterableOnce[Int]
我们提供
Try[Int] => Try[Int]
因为n.map((p: Int) => p)
返回Try[Int]
.现在,以下的理解是完全不同的野兽
because n.map((p: Int) => p)
returns Try[Int]
. Now the following for-comprehension is a whole different beast
for {
n <- test
p <- n
} println(p)
由于缺少yield
,因此对
because of the absence of yield
it desugars to
test.foreach((n: Try[Int]) => n.foreach((p: Int) => println(p)))
其中foreach
需要一个类型的函数
where foreach
expects a function of type
Try[Int] => Unit
我们确实提供了
,因为n.foreach((p: Int) => println(p))
确实返回了Unit
.
which we indeed provide because n.foreach((p: Int) => println(p))
indeed returns Unit
.