Swift中如何在if else块初始化带关联类型的协议非可选变量?
这个问题我之前在项目里碰到过好几次,核心原因很明确:带Self或关联类型约束的协议,Swift不允许直接把它当作变量的具体类型来用——编译器会把这类协议归类为“只能用作泛型约束”的范畴。下面给你几个实用的解决方案,既能实现你要的延迟初始化逻辑,又能彻底避免代码重复:
解决方案1:用泛型函数封装分支逻辑
这是最简洁的方案,把创建Mutation和调用set(mutation:)的逻辑封装到一个泛型函数里,利用泛型约束适配不同的协议实现类型,完全避免重复代码:
// 封装一个泛型函数,接收任意符合GraphQLMutation的类型 func applyMutation<T: GraphQLMutation>(_ mutation: T) { self.graphQLDataSource.set(mutation: mutation) } // 调用的时候直接根据分支传入对应实例 if something { applyMutation(StartMutation()) } else { applyMutation(StopMutation()) }
这种方法不需要额外定义新类型,代码清爽,而且完美贴合你避免重复调用set方法的需求。
解决方案2:类型擦除(Type Erasure)
如果你必须把Mutation实例存储为变量(而不是直接传入set方法),可以用类型擦除的方式,创建一个包装器把带关联类型的协议转化为具体类型:
首先定义类型擦除的结构体,需要实现GraphQLMutation协议的所有关联类型和方法,把内部实例的逻辑转发出去:
struct AnyGraphQLMutation: GraphQLMutation { // 先匹配协议要求的关联类型(根据你的GraphQLMutation实际定义调整) typealias Input = Any // 假设协议有Input关联类型,这里用Any或具体类型适配 typealias Output = Any // 用闭包存储原实例的方法,实现转发 private let _perform: () async throws -> Output private let _input: Input // 初始化方法,接收任意符合GraphQLMutation的实例 init<T: GraphQLMutation>(_ mutation: T) where T.Input == Input, T.Output == Output { _perform = mutation.perform _input = mutation.input } // 实现协议要求的方法,转发给内部闭包 func perform() async throws -> Output { try await _perform() } // 实现协议要求的属性 var input: Input { _input } }
之后就可以正常延迟初始化变量了:
let mutation: AnyGraphQLMutation if something { mutation = AnyGraphQLMutation(StartMutation()) } else { mutation = AnyGraphQLMutation(StopMutation()) } self.graphQLDataSource.set(mutation: mutation)
这种方案适合需要存储协议实例的场景,但缺点是需要手动实现包装器的所有协议方法,会有点繁琐。
方案3:直接在分支内调用set(不推荐,但简单)
如果你的场景不需要存储Mutation变量,只是要调用set方法,也可以直接在分支里执行,但这样会有重复代码,只适合逻辑非常简单的场景:
if something { self.graphQLDataSource.set(mutation: StartMutation()) } else { self.graphQLDataSource.set(mutation: StopMutation()) }
显然方案1是最符合你需求的选择,既简洁又能避免代码重复。
内容的提问来源于stack exchange,提问作者matmat
相关产品推荐
相关产品推荐

