Swift中Resolver泛型工厂如何实现同名方法返回Weak包装值?
如何为Resolver类实现同名resolve方法返回Weak包装实例?
你遇到的问题是Swift函数重载规则导致的:仅返回类型不同不足以区分两个重载函数。你的两个resolve泛型方法都没有参数,编译器无法通过返回值T和Weak<T>来推断应该调用哪一个,因此出现类型错误。
错误原因详解
原代码中,两个resolve方法的签名本质上都是无参数的泛型方法:
- 主类的
resolve<T>() -> T:泛型参数T对应返回的实例类型 - 扩展的
resolve<T>() -> Weak<T>:泛型参数T对应Weak包装的实例类型
Swift编译器无法仅通过返回值类型来区分这两个方法,导致赋值给Weak<Service>时无法确定调用哪个重载。
修正方案
下面提供两种可行的解决方式,都能保留同名方法的设计:
方案1:添加区分性参数(推荐,调用更简洁)
给扩展的resolve方法添加一个带默认值的参数,让编译器能通过参数区分重载,同时不增加调用复杂度:
extension Resolver { func resolve<T: AnyObject>(weakOf type: T.Type = T.self) -> Weak<T> { Weak<T>(self.resolve()) } }
调用方式:
// 方式1:利用类型推断,自动匹配 let weakS: Weak<Service> = resolver.resolve() // 方式2:显式指定类型,更直观 let weakS = resolver.resolve(weakOf: Service.self)
方案2:显式指定泛型参数
修改扩展方法的泛型参数名(可选,仅为了更清晰),调用时显式指定泛型参数,让编译器明确目标方法:
extension Resolver { func resolve<Wrapped: AnyObject>() -> Weak<Wrapped> { Weak<Wrapped>(self.resolve()) } }
调用方式:
let weakS: Weak<Service> = resolver.resolve<Service>()
验证修正后的代码
完整可运行代码示例:
class Service { func action() { print("action in service") } required init() { } } class Resolver { typealias Factory = () -> Any private var registrations = [String: Factory]() func register(factory: @escaping Factory, forType type: Any.Type) { registrations[key(for: type)] = factory } func resolve<T>() -> T { let key = key(for: T.self) guard let factory = registrations[key], let result = factory() as? T else { fatalError("No registration found for type \(T.self)") } return result } private func key(for type: Any.Type) -> String { return ObjectIdentifier(type).debugDescription } } class Weak<T: AnyObject> { private(set) weak var obj: T? init(_ obj: T) { self.obj = obj } } // 使用方案1的扩展 extension Resolver { func resolve<T: AnyObject>(weakOf type: T.Type = T.self) -> Weak<T> { Weak<T>(self.resolve()) } } let resolver = Resolver() resolver.register(factory: { Service() }, forType: Service.self) let s: Service = resolver.resolve() let weakS: Weak<Service> = resolver.resolve() s.action() // 输出:action in service weakS.obj?.action() // 输出:action in service
内容的提问来源于stack exchange,提问作者Andrew Romanov
相关产品推荐
相关产品推荐

