基于Cats Effect,如何为可变集合实现返回IO[Boolean]的filter/filterInPlace?
问题场景
原同步过滤场景代码:
val ds = mutable.Set[Int](1, 2, 3, 4, 5) def check(num: Int): Boolean = num % 2 == 0 ds.filter(check)
现在check函数返回Cats Effect的IO[Boolean]:
def check(num: Int): IO[Boolean] = IO.delay(num % 2 == 0)
请问该如何实现对应的filter或filterInPlace方法?
解决方案
由于校验逻辑现在是异步的(返回IO类型),无法直接使用原生集合的同步方法,需要结合Cats Effect的异步操作来实现:
1. 生成新过滤集合(返回IO[mutable.Set[Int]])
遍历集合元素,异步执行校验后,收集符合条件的元素生成新的可变集合:
import cats.effect.IO import scala.collection.mutable val ds = mutable.Set[Int](1, 2, 3, 4, 5) def check(num: Int): IO[Boolean] = IO.delay(num % 2 == 0) val filteredSetIO: IO[mutable.Set[Int]] = IO.traverse(ds.toList)(num => check(num).map((num, _))) .map(pairs => mutable.Set.from(pairs.collect { case (num, true) => num }))
先用IO.traverse将每个元素与异步校验结果配对,再过滤出校验通过的元素,转换为可变集合。
2. 原地修改集合(返回IO[Unit])
如果需要直接修改原集合,需将整个修改逻辑包裹在IO中,确保所有异步校验完成后再执行集合修改:
val filterInPlaceIO: IO[Unit] = IO.traverse(ds.toList)(num => check(num).map(num -> _)) .map(pairs => { val toRemove = pairs.collect { case (num, false) => num } ds --= toRemove })
先收集所有校验不通过的元素,再一次性从原集合中移除,避免异步过程中修改集合引发的异常。
注意事项
- 原生可变集合并非线程安全,若在多线程环境下使用,需结合
IO的线程安全特性,或替换为线程安全集合。 - 遍历前将集合转为
List,是为了避免遍历过程中集合被修改导致的遍历异常。
内容的提问来源于stack exchange,提问作者Shivam
相关产品推荐
相关产品推荐

