Swift 4中递归泛型结构体Lock支持多类型参数初始化的改造问题
解决Swift Lock结构体支持不同Element类型参数初始化的问题
首先看你给出的原始Lock结构体代码:
struct Lock<Element: Hashable> { var element: Element init(_ element: Element, _ args:[Lock<Element>]? = nil) { self.element = element } }
问题出在初始化方法的args参数上——它被约束为[Lock<Element>],意味着传入的数组里所有Lock的Element类型必须和当前创建的Lock完全一致,所以Lock("element", [Lock(100)])会报错,因为String和Int类型不匹配。
要实现支持不同Element类型的参数,我们可以通过两种方式修改,取决于你是否需要存储这些args:
方案1:仅支持初始化时传入不同类型(不存储args)
如果不需要在结构体里保存args,只需要把初始化方法改成泛型,让args的类型独立于当前Lock的Element即可:
struct Lock<Element: Hashable> { var element: Element // 用泛型T分离args的类型约束 init<T: Hashable>(_ element: Element, _ args: [Lock<T>]? = nil) { self.element = element // 这里可以添加对args的临时处理逻辑,比如打印、验证等 } }
现在你就能正常运行这些代码了:
// 成功编译:String类型的Lock接受Int类型的Lock数组 let lock1 = Lock("element", [Lock(100)]) // 原来同类型的场景也不受影响 let lock2 = Lock("element", [Lock("100")])
方案2:需要存储不同类型的args(结合类型擦除)
如果需要把这些不同类型的Lock保存到结构体里,由于Swift不允许直接把不同泛型参数的Lock放到同一个数组中,我们需要用类型擦除来统一类型:
首先定义一个类型擦除的包装结构体:
struct AnyLock { // 用any Hashable统一存储任意Lock的element let underlyingElement: any Hashable init<Elem: Hashable>(_ lock: Lock<Elem>) { self.underlyingElement = lock.element } }
然后修改Lock结构体,添加存储args的属性,并调整初始化方法:
struct Lock<Element: Hashable> { var element: Element // 用AnyLock数组存储不同类型的Lock var associatedLocks: [AnyLock]? init<T: Hashable>(_ element: Element, _ args: [Lock<T>]? = nil) { self.element = element self.associatedLocks = args?.map(AnyLock.init) } }
这样不仅能接受不同类型的Lock数组,还能把它们的元素存储起来:
// 支持混合类型的Lock数组 let lock3 = Lock(100, [Lock(true), Lock(3.14), Lock("hello")]) // 访问存储的元素时,可以用类型转换 if let boolElement = lock3.associatedLocks?.first?.underlyingElement as? Bool { print(boolElement) // 输出:true }
总结一下,核心思路就是打破args参数和当前Lock的Element类型绑定,通过泛型分离约束,再结合类型擦除解决不同类型的存储问题。
内容的提问来源于stack exchange,提问作者Sasha
相关产品推荐
相关产品推荐

