如何将Scala的Iterable[T]转换为Option[Iterable[S]](要求所有T都是S实例)
实现方案
你需要的功能可以通过以下两种方式实现:
1. 基于Cats实现
结合Cats的Traverse类型类的短路特性即可实现,只要遍历过程中遇到第一个不符合类型要求的元素,就会直接返回None:
import cats.implicits._ import scala.reflect.ClassTag def allInstanceOf[F[_]: Traverse, T, S: ClassTag](fa: F[T]): Option[F[S]] = fa.traverse { case s: S => Some(s) case _ => None } // Set场景调用示例 val intSet: Set[Any] = Set(1, 2, 3) val validRes: Option[Set[Int]] = allInstanceOf[Set, Any, Int](intSet) // 输出Some(Set(1,2,3)) val mixedSet: Set[Any] = Set(1, "2", 3) val invalidRes: Option[Set[Int]] = allInstanceOf[Set, Any, Int](mixedSet) // 输出None
代码中的ClassTag用于规避Scala泛型擦除导致的运行时类型校验失效问题。
2. 纯Scala标准库实现
如果不想引入Cats依赖,也可以用原生集合方法实现相同逻辑:
import scala.reflect.ClassTag def setAllInstanceOf[T, S: ClassTag](set: Set[T]): Option[Set[S]] = { val (hasInvalid, converted) = set.foldLeft((false, Set.empty[S])) { case ((invalidFlag, acc), elem) => if (invalidFlag) (true, acc) else elem match { case s: S => (false, acc + s) case _ => (true, acc) } } Option.when(!hasInvalid)(converted) }
方案符合要求的原因
- 集合中存在任意非
S类型的元素时,直接返回None,不会过滤有效元素返回部分结果 - 所有元素均为
S类型时,才返回包装了完整转换后集合的Some值 - 原生支持
Set[T]场景,也可以快速扩展到其他Iterable类型
内容的提问来源于stack exchange,提问作者Roberto Tyley
相关产品推荐
相关产品推荐

