Swift中自定义JSONValue协议处理数组时的类型兼容问题
Swift中JSONValue协议数组扩展的问题解析
问题背景
我在开发中定义了一套JSON处理的类型:
typealias JSONObject = [String:JSONValue] protocol JSONValue {} extension String: JSONValue {} extension Int: JSONValue {} extension Double: JSONValue {} extension Bool: JSONValue {} extension NSNull: JSONValue {} extension JSONObject: JSONValue {}
为了支持数组类型,我最初加了这样的扩展:
extension [JSONValue]: JSONValue {}
大部分场景正常,但在处理[JSONObject]类型的数组时出现报错:
var myObject = JSONObject() myObject["primitive"] = "OK" myObject["array"] = ["OK"] let myObjectAsJSONValue: JSONValue = myObject // 正常运行 var myArray = [JSONObject]() myArray.append(myObject) let myArrayAsJSONValue: JSONValue = myArray // 报错:协议'JSONValue'要求类型'JSONObject'与'any JSONValue'等价
后来我把数组扩展改成下面的写法就解决了问题,但不清楚两者的差异:
extension Array : JSONValue where Element : JSONValue {}
错误原因拆解
你最初写的extension [JSONValue]: JSONValue {},本质是给具体的数组类型[JSONValue]添加协议遵循——只有当数组的静态类型明确是[JSONValue]时,它才符合JSONValue协议。
而[JSONObject]是另一个完全不同的数组类型,虽然JSONObject遵循JSONValue,但Swift的数组类型是严格区分元素类型的,数组本身不支持协变(简单说就是[JSONObject]不能被当成[JSONValue]看待,除非你显式转换)。所以[JSONObject]并没有被你的第一个扩展覆盖,自然无法赋值给JSONValue类型的变量。
两种扩展的核心差异
1. 第一种扩展:针对具体类型的扩展
extension [JSONValue]: JSONValue {}
- 作用范围:仅对元素是
JSONValue的数组生效,也就是只有[JSONValue]这个具体类型能遵循JSONValue。 - 局限性:像
[JSONObject]、[String]这类元素遵循JSONValue但静态类型不是[JSONValue]的数组,都不会自动获得JSONValue的遵循资格。
2. 第二种扩展:带泛型约束的扩展
extension Array : JSONValue where Element : JSONValue {}
- 作用范围:这是一个泛型约束扩展,只要数组的元素类型遵循JSONValue,这个数组类型就自动遵循JSONValue。
- 灵活性:不管是
[JSONValue]、[JSONObject]、[String]还是[Int],只要它们的元素符合JSONValue,对应的数组类型都会被这个扩展覆盖,自然可以赋值给JSONValue类型的变量。
你遇到的场景中,[JSONObject]的元素JSONObject已经遵循JSONValue,所以第二种扩展会自动让[JSONObject]也遵循JSONValue,赋值操作也就正常了。
内容的提问来源于stack exchange,提问作者Thomas Albert
相关产品推荐
相关产品推荐

