泛型类型约束与继承

Generics type constraint vs inheritance

这两个函数声明有区别吗?

func doSomething<T: UIViewController>(controller: T) {...}

对比

func doSomething(controller: UIViewController) {...}

Apples Swift programming language 书中的 Type Constraint Syntax 部分中,有以下代码示例:

func​ ​someFunction​<​T​: ​SomeClass​, ​U​: ​SomeProtocol​>(​someT​: ​T​, ​someU​: ​U​) {
    // function body goes here
}

具有以下描述:

The hypothetical function above has two type parameters. The first type parameter, T, has a type constraint that requires T to be a subclass of SomeClass. ...

那么在哪些情况下使用上述泛型函数更好?

它们是不同的,但就您使用它们的方式而言,它们的结果几乎完全相同。

不同之处在于,当您调用泛型版本时,编译器会将 T 静态设置为作为参数传入的任何类型。在该参数上调用方法时,这几乎没有区别——无论哪种方式,对其方法的调用都将被动态调度,并且您不能触及 T 中不能保证从约束中可用的任何部分.

但是假设您对此方法进行了更改,不仅接受一个参数,而且 return 一个相同类型的参数:

// T here will take the type of whatever is going in/out of the function
// be that UIViewController or a subtype of it
func doSomethingGenerically<T: UIViewController>(controller: T) -> T {  
    // some logic that results in a new controller being returned
}

// here the return type is fixed to be UIViewController
func doSomethingViaBaseClass(controller: UIViewController) -> UIViewController {  
    // some logic that results in a new controller being returned
}

现在,假设您有一个要传入的 UIViewController 的子类,如下所示:

let subClass: MyUIViewController = ...

let controller1 = doSomethingGenerically(subClass)

let controller2 = doSomethingViaBaseClass(subClass)

在这里,变量 controller1 的类型将是 MyUIViewController,因为这是传递给函数的类型,所以 T 也是。但是变量 controller2 的类型将是 UIViewController 因为这是 doSomethingViaBaseClass returns.

的固定类型

请注意,这并不意味着它们引用 的对象会有所不同——这取决于函数体实现的内容。只是 引用 的变量类型会发生变化。

还有其他细微差别,但这是需要了解的主要差别。然而,在结构的情况下,有更多值得注意的差异。碰巧我昨天写了 an article 关于他们的文章,这可能会有所帮助。