分类中添加约束?
例如, 有一个 Array<SomeType>
类型(Element
为 SomeType
)的数组, 而我只想让这种类型的数组遵守 SomeProtocol
协议. 理想情况下, 应该这么写:
extension Array: SomeProtocol where Element : SomeType {
func someMethod() {
}
}
但事实上并不能这么写, Xcode会报一个error:
Extension of type 'Array' with constraints cannot have an inheritance clause
声明中添加约束
既然分类中不可以,那么对于自定义的类型, 在声明中就可行吗?
如果是在声明中使用泛型的类型约束, 应该是这么写:
实现
class TestClass<ObjectType>: SomeProtocol where ObjectType : SomeType {
func testMethod() {
}
}
protocol SomeProtocol {
func testMethod();
}
编译通过, 测试下试试:
let test1: TestClass<String>; // error: ❗️'TestClass' requires that 'String' inherit from 'NSObject'
let test2: TestClass<SomeType>;
test2.testMethod();
缺点
可以看到, 在声明中使用类型约束, 可以实现一定的效果, 但是这么操作有很大的局限性: 1. 不能对非自定义类型使用. 2. 会将泛型强制规定为这一类型.
较完美的方案
难道就没有一种完美
的实现方案吗?
在电光石火间, 我抓住了灵感的一瞬:
实现
extension TestClass: SomeProtocol {
func testMethod() {
print("ObjectType isn't SomeType")
}
}
extension TestClass where ObjectType : SomeType {
func testMethod() {
print("ObjectType is SomeType!");
}
}
test:
let test1: TestClass<NSObject> = TestClass();
let test2: TestClass<SomeType> = TestClass();
test1.testMethod(); // ObjectType isn't SomeType
test2.testMethod(); // ObjectType is SomeType!
缺点
这个方案可以比较好的实现我们的需求, 唯一的缺点就是, 由于遵守协议时不能使用类型约束, 导致其他类型也可以使用协议内函数与变量.
相关
stackoverflow
上也有同学给出了另一种思路.
同时, Swift
团队也把这项优化添加到了swift-evolution
中, 相信在 Swfit4
中就能看到: Generics improvements needed by the standard library.