美文网首页
Subtype existential

Subtype existential

作者: 醉看红尘这场梦 | 来源:发表于2020-03-23 11:38 被阅读0次

在Objective-C里,声明变量的时候,我们可以用下面的形式表达类型和protocol的关系:

id<Protocol1, Protocol2>
Base<Protocol>*

例如,第一个就表示任意遵从Protocol1Protocol2的类型,第二个则表示遵从ProtocolBase类。为了实现同样的功能,SE-0156为Swift 4添加了下面的特性。

用AnyObject约束任意遵从protocol的类

当我们要约束任意一个遵从P的类时,可以这样:

protocol P {}
struct S : P {}
class C : P {}
class D { }

let u: AnyObject & P = C()
let v: P & AnyObject = C()

在上面的例子里,AnyObject表示任意一个classP表示要遵从的protocol,用&把它们连接起来,就达成了我们要对类型进行的约束。不过,就像你看到的一样,它们的先后并没有关系。理解了它的含义之后,就不难理解,下面的代码,都会触发编译错误:

// !! Compile time error: `S` is not a class !!
let t: AnyObject & P = S()
// !! Compile time error: `D` is not conform to P !!
let w: AnyObject & P = D()

用具体的类名约束遵从protocol的类以及派生类

除了AnyObject之外,我们也可以限制某个遵从了protocol的具体类以及它的派生类,像这样:

protocol P {}
struct S : P {}
class C {}
class D: P {}
class E: C, P {}

let w: C & P = E()

其中,C & P这样的写法,表示遵从了protocol P的类C以及C的派生类。因此,下面两种情况都会导致编译错误:

首先,不能限制struct类型的protocol约束:

let u: S & P

其次,不是的C的派生类无法通过编译:

let v: C & P = D()

另外,当我们在protocol约束中,同时使用了AnyObject和具体的类名,则具体的类名会覆盖AnyObject,也就是说,下面这两种表达方式是相同的:

let w: C & P = E()
let w: AnyObject & C & P = E()

而下面的代码同样无法通过编译:

let v: AnyObject & C & P = D()

实际上,关于protocol-constraints的用法,还有一些更复杂的情况,例如,在约束中串联多个class或者typealias,大家可以在SE-0165中找到关于这个特性的详细规格。这里,我们就不一一展开了,最重要的是,我们要知道,在Swift 4里,多了一种可以进一步约束类型的用法。

带来的潜在影响

基于这个特性,之前的一些Objective-C的代码桥接到Swift 4,采用protocol-constraints语法的时候,会带来源代码的不兼容。来看下面的例子:

@interface MyViewController
- (void)setup:(
    nonnull UIViewController<
    UITableViewDataSource,
    UITableViewDelegate>*)tableViewController;
@end

当上面这段代码桥接到Swift 3时,会忽略掉setup参数的UITableViewDataSourceUITableViewDelegate的约束,变成这样:

class MyViewController {
    func setup(
        tableViewController: UIViewController) {}
}

于是,在Swift里,我们可以给setup传递任何一个UIViewController对象,甚至这个对象没有遵从UITableViewDataSourceUITableViewDelegate

但桥接到Swift 4后,MyViewController就会变成这样:

class MyViewController {
    func setup(
        tableViewController:
            UIViewController &
            UITableViewDataSource &
            UITableViewDelegate) {}
}

这时,对于那些没有遵从UITableViewDataSourceUITableViewDelegateUIViewController对象,如果传递给setup,就无法通过编译了。

相关文章

网友评论

      本文标题:Subtype existential

      本文链接:https://www.haomeiwen.com/subject/uviuehtx.html