Swift中能否将泛型函数返回类型替换为带约束的typealias?
Swift 复用泛型约束的可行方案
你遇到的场景是:定义了TypedPoint和TypedVector两个协议,扩展中的+、-运算符都需要重复指定「TVector遵循TypedVector且TUnit与TypedPoint的TUnit匹配」的泛型约束,希望通过带约束的typealias简化重复代码,但直接写法编译失败。
Swift目前不支持直接定义带协议约束的typealias来替代泛型参数约束(比如<TVector: MyConstrainedAlias>这种写法不符合语法),但可以通过两种方式实现约束复用:
方案一:用关联类型封装约束
在TypedPoint协议中定义关联类型,直接绑定与自身TUnit匹配的TypedVector类型,这样扩展运算符时无需重复写约束:
protocol TypedPoint { associatedtype TUnit: Numeric // 关联类型直接约束:必须是TUnit匹配的TypedVector associatedtype CompatibleVector: TypedVector where CompatibleVector.TUnit == TUnit var x: TUnit { get set } var y: TUnit { get set } } protocol TypedVector { associatedtype TUnit: Numeric var dx: TUnit { get set } var dy: TUnit { get set } } // 扩展运算符时直接用Self.CompatibleVector,无需额外约束 extension TypedPoint { static func +(lhs: Self, rhs: Self.CompatibleVector) -> Self { Self(x: lhs.x + rhs.dx, y: lhs.y + rhs.dy) } static func -(lhs: Self, rhs: Self.CompatibleVector) -> Self { Self(x: lhs.x - rhs.dx, y: lhs.y - rhs.dy) } } // 实现TypedPoint时,指定对应的CompatibleVector struct Point<Unit: Numeric>: TypedPoint { typealias CompatibleVector = Vector<Unit> var x: Unit var y: Unit } struct Vector<Unit: Numeric>: TypedVector { var dx: Unit var dy: Unit }
方案二:泛型typealias配合where子句(Swift 5.7+)
利用Swift 5.7新增的泛型typealias支持where子句的特性,先定义绑定特定Unit的TypedVector别名,再在运算符中复用:
protocol TypedPoint { associatedtype TUnit: Numeric var x: TUnit { get set } var y: TUnit { get set } } protocol TypedVector { associatedtype TUnit: Numeric var dx: TUnit { get set } var dy: TUnit { get set } } // 定义绑定特定Unit的TypedVector别名 typealias CompatibleVector<Unit> = TypedVector where TypedVector.TUnit == Unit // 扩展运算符时,复用该别名简化约束 extension TypedPoint { static func +<Unit>(lhs: Self, rhs: CompatibleVector<Unit>) -> Self where Self.TUnit == Unit { Self(x: lhs.x + rhs.dx, y: lhs.y + rhs.dy) } static func -<Unit>(lhs: Self, rhs: CompatibleVector<Unit>) -> Self where Self.TUnit == Unit { Self(x: lhs.x - rhs.dx, y: lhs.y - rhs.dy) } }
这种写法虽然仍需在函数中添加Self.TUnit == Unit的约束,但比重复写完整的TVector: TypedVector where TVector.TUnit == Self.TUnit要简洁很多。
内容的提问来源于stack exchange,提问作者Mark A. Donohoe
相关产品推荐
相关产品推荐

