为泛型类型遵守协议添加类型约束

分类中添加约束?

例如, 有一个 Array<SomeType> 类型(ElementSomeType)的数组, 而我只想让这种类型的数组遵守 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.

订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x