特定
val strings = Set("Hi", "there", "friend")
def numberOfCharsDiv2(s: String) = scala.util.Try {
if (s.length % 2 == 0) s.length / 2 else throw new RuntimeException("grr")
}
Run Code Online (Sandbox Code Playgroud)
为什么我不能flatMap离开方法调用产生的Try?即
strings.flatMap(numberOfCharsDiv2)
<console>:10: error: type mismatch;
found : scala.util.Try[Int]
required: scala.collection.GenTraversableOnce[?]
strings.flatMap(numberOfCharsDiv2)
Run Code Online (Sandbox Code Playgroud)
要么
for {
s <- strings
n <- numberOfCharsDiv2(s)
} yield n
<console>:12: error: type mismatch;
found : scala.util.Try[Int]
required: scala.collection.GenTraversableOnce[?]
n <- numberOfCharsDiv2(s)
Run Code Online (Sandbox Code Playgroud)
但是,如果我使用Option而不是Try,则没有问题.
def numberOfCharsDiv2(s: String) = if (s.length % 2 == 0)
Some(s.length / 2) else None
strings.flatMap(numberOfCharsDiv2) # => Set(1, 3)
Run Code Online (Sandbox Code Playgroud)
尝试不允许使用flatMap的原因是什么?
Kig*_*gyo 11
让我们来看看签名flatMap.
def flatMap[B](f: (A) => GenTraversableOnce[B]): Set[B]
Run Code Online (Sandbox Code Playgroud)
你的numberOfCharsDiv2被视为String => Try[Int].Try不是它的子类,GenTraversableOnce这就是你得到错误的原因.你并不需要一个Set仅仅因为你flatMap在a上使用的函数Set.该函数基本上必须返回任何类型的集合.
那为什么它可以使用Option?Option也不是子类GenTraversableOnce,但在Option伴随对象内部存在隐式转换,将其转换为List.
implicit def option2Iterable[A](xo: Option[A]): Iterable[A] = xo.toList
Run Code Online (Sandbox Code Playgroud)
然后还有一个问题.为什么不进行隐式转换Try呢?因为你可能得不到你想要的东西.
flatMap可以看作是一个map跟着的flatten.
想象一下,你有一个List[Option[Int]]喜欢List(Some(1), None, Some(2)).然后flatten会给你List(1,2)类型List[Int].
现在看一个例子Try.List(Success(1), Failure(exception), Success(2))类型List[Try[Int]].
现在如何解决失败的问题?
None吗?那为什么不直接用Option?List(1, exception, 2).这里的问题是,该类型List[Any]的,因为你必须找到一个共同的超类Int和Throwable.你失去了类型.这些应该是没有隐式转换的原因.当然,如果您接受上述后果,您可以自由定义一个.
问题在于,在您的示例中,您不是在尝试平面图.你正在做的平面图超过了Set.
Flat的Overmap采用Set [A],函数从A到Set [B].正如Kigyo在下面的评论中指出的那样,这不是Scala中Set的实际类型签名,但平面地图的一般形式是:
M[A] => (A => M[B]) => M[B]
也就是说,它需要一些更高级的类型,以及对更高级别类型的类型元素进行操作的函数,并且它使用映射元素返回相同的高级类型.
在您的情况下,这意味着对于Set的每个元素,flatmap需要调用一个带有String的函数,并返回一个类型B的Set,它可以是String(或者可以是其他任何东西).
你的功能
numberOfCharsDiv2(s: String)
Run Code Online (Sandbox Code Playgroud)
正确接受一个字符串,但错误地返回一个Try,而不是另一个Set作为flatmap需要.
如果您使用'map',您的代码将起作用,因为这允许您采用某种结构 - 在这种情况下,在每个元素上设置并运行一个函数,将其从A转换为B而不使函数的返回类型符合封闭结构,即返回一套
strings.map(numberOfCharsDiv2)
res2: scala.collection.immutable.Set[scala.util.Try[Int]] = Set(Success(1), Failure(java.lang.RuntimeException: grr), Success(3))
| 归档时间: |
|
| 查看次数: |
3645 次 |
| 最近记录: |