为什么向Set#intersection传入Sequence与传入Set时行为存在差异?
Swift Set.intersection 入参类型差异导致结果异常问题
问题背景
Set 数据结构的 intersection 方法官方接口声明支持 Sequence、Set 两种类型的入参,但实际运行时两类入参的执行逻辑存在差异,会导致返回结果不符合预期。
复现代码
在任意Swift REPL环境执行以下代码即可复现该现象:
// 入参为Array(遵循Sequence协议) Set([3, 6, 0, 1, 5, 2, 4]).intersection([0, 1, 1, 2, 3, 4, 5]) // 返回结果共7个元素,错误包含入参序列中不存在的6 // $R0: Set<Int> = 7 values { // [0] = 5 // [1] = 0 // [2] = 3 // [3] = 1 // [4] = 2 // [5] = 6 // [6] = 4 // } // 入参为Set类型 Set([3, 6, 0, 1, 5, 2, 4]).intersection(Set([0, 1, 1, 2, 3, 4, 5])) // 返回结果共6个元素,符合交集计算预期 // $R1: Set<Int> = 6 values { // [0] = 1 // [1] = 5 // [2] = 0 // [3] = 4 // [4] = 2 // [5] = 3 // }
异常表现
- 传入Sequence类型入参时,返回结果错误保留了调用方Set中存在、但入参序列里完全不存在的元素
6,不符合交集的数学定义 - 传入Set类型入参时,返回结果完全正确
- 两次调用的唯一区别为入参是否提前转换为Set类型
问题定性
这属于Swift标准库的实现bug,并非对方法用法的理解偏差。
该bug的诱因是接收Sequence入参的intersection重载版本存在逻辑错误:实现过程中没有基于入参序列的元素做存在性校验,错误保留了调用方自身集合中不符合交集规则的元素,导致结果错误。
临时规避方案:调用intersection方法时,如果入参不是Set类型,先手动将其转换为Set后再传入,即可得到正确计算结果。
内容的提问来源于stack exchange,提问作者Bill
相关产品推荐
相关产品推荐

