Swift Combine的compactMap失效问题(Xcode13下assign(to:)场景复现)
结论
这不是Combine的Bug,是Swift类型推断的隐式可选提升机制导致的符合语言规则,但不符合开发者直觉的表现。
核心原因
assign(to: &self.$latest1)要求上游Publisher的输出类型必须和latest1的String?类型匹配- 上游
$current的输出值为String?类型,你未加类型标注写compactMap { $0 }时,编译器为了让整个链路的输出匹配String?的要求,会自动把闭包返回的$0(原类型String?)隐式提升为String??(双重可选) - 此时
compactMap只会过滤String??层级的nil:当current赋值为nil时,传入闭包的$0是String?的.none,被提升为String??的.some(.none),不属于compactMap要过滤的nil,因此会把内部的String?类型nil传递到下游,赋值给latest1,就出现了你看到的不符合compactMap语义的表现。
修复方案原理
- 显式指定闭包返回类型:你主动标注
compactMap闭包返回String?,编译器不会做隐式双重可选提升,此时compactMap的输出类型为String,current为nil时闭包返回的nil会被compactMap过滤,不会向下游传递,String类型可以自动桥接为String?完成赋值。 - 中间增加map操作:
compactMap后加map { $0 }时,类型推断会优先处理compactMap + map的局部链路,不会被下游assign的类型要求影响,compactMap { $0 }会按直觉被推断为输出String类型,nil被过滤后不会向下传递。
避坑提示
涉及可选值的Combine链式调用如果出现不符合操作符语义的异常,优先打印检查每个操作符的输出类型是否符合你的预期,必要时显式标注闭包返回类型强制编译器按你的预期推导。
内容的提问来源于stack exchange,提问作者Darko
相关产品推荐
相关产品推荐

