Swift技术问询:能否将`Self`约束为泛型类型?
如何在Swift中将
Self约束为泛型类型? 当然有办法啦!在Swift里,我们可以通过协议关联类型、泛型方法约束,或者泛型基类这几种方式,实现把Self和特定泛型类型绑定的效果。结合你给出的鸟类协议代码,我来给你具体拆解说明~
先把你提供的代码补全方便后续参考:
protocol Bird { var name: String { get } var canFly: Bool { get } func doSomething() } protocol Flyable { var airspeedVelocity: Double { get } } extension Bird { // Flyable birds can fly! var canFly: Bool { return self is Flyable } func doSomething() { print("default Bird: \(name)") } } class FlappyBird: Bird, Flyable { let name: String let canFly = true var airspeedVelocity: Double = 5.0 init(name: String) { self.name = name } }
1. 用协议关联类型约束Self
如果想让协议的实现类必须和某个泛型类型绑定,可以给协议添加关联类型,再通过where子句约束Self与关联类型匹配:
protocol Bird { associatedtype FlyCapability: Flyable // 关联一个符合Flyable的泛型类型 var name: String { get } var canFly: Bool { get } func doSomething() func flyWithCapability(_ capability: FlyCapability) } // 扩展中约束Self既是Flyable,同时关联类型就是Self本身 extension Bird where Self: Flyable, Self.FlyCapability == Self { var canFly: Bool { return true } func flyWithCapability(_ capability: Self) { print("\(name) is flying at \(capability.airspeedVelocity) mph") } }
这样一来,只有当Bird的实现类(比如FlappyBird)同时符合Flyable,并且把关联类型FlyCapability指定为自己时,才能使用这个扩展里的方法,相当于把Self约束成了泛型关联类型。
2. 在泛型方法中约束Self
如果只是在某个方法层面需要约束Self为泛型类型,可以在方法的where子句里直接限定Self的类型:
extension Bird { // 约束调用这个方法的Self必须符合Flyable,同时交互对象也得是会飞的Bird func interact<T: Bird>(with partner: T) where Self: Flyable, T: Flyable { print("\(self.name) and \(partner.name) are flying together happily!") } }
这里的where Self: Flyable就把当前调用方法的Self约束成了符合Flyable的泛型类型范畴。
3. 借助泛型基类约束子类Self
如果是类的场景,我们可以写一个泛型基类,让子类继承时把泛型参数指定为Self,从而实现约束:
// 泛型基类,要求泛型参数符合Flyable class GenericBird<T: Flyable>: Bird { let name: String let flyCapability: T init(name: String, capability: T) { self.name = name self.flyCapability = capability } var canFly: Bool { return true } func doSomething() { print("\(name) uses its flying capability to soar!") } } // 让FlappyBird继承泛型基类,同时把泛型参数指定为Self(自己) class FlappyBird: GenericBird<FlappyBird>, Flyable { var airspeedVelocity: Double = 5.0 init(name: String) { super.init(name: name, capability: self) } }
这里GenericBird<FlappyBird>就把泛型类型T绑定成了Self(FlappyBird本身),同时因为FlappyBird符合Flyable,完美满足了泛型约束。
总结一下,这几种方式都能实现把Self约束为泛型类型的需求,具体用哪一种,就看你的业务场景和代码结构啦~
内容的提问来源于stack exchange,提问作者user6902806
相关产品推荐
相关产品推荐

