Swift 2.0中的泛型

Kir*_*air 9 generics ios swift swift2

我已经浏览了Apple开发者网站上的Swift教程,但我不理解泛型的概念.有人能够以简单的方式解释它吗?例如:

func swapTwoValues<T>(inout a: T, inout b: T) {
    let temporaryA = a
    a = b
    b = temporaryA
}
Run Code Online (Sandbox Code Playgroud)

ABa*_*ith 11

如果不在您给出的示例中使用泛型,则必须为swapTwoValues要交换的每种类型重载.例如:

func swapTwoValues(inout a: Int, inout b: Int) {
    let temp = a
    a = b
    b = temp
}

func swapTwoValues(inout a: String, inout b: String) {
    let temp = a
    a = b
    b = temp
} 

// Many more swapTwoValues functions...
Run Code Online (Sandbox Code Playgroud)

上述函数之间唯一不同的是它们接受的类型; 每个内部的代码完全相同.因此,最好编写一个可以采用任何类型的通用函数.

要注意,你不能代替是很重要的TAny.没有保证,a并且b将是相同的类型 - 例如,你无法交换a Int和a String.


ske*_*ech 4

在您的示例中,T 代表一种类型。一旦设置,该类型对于整个函数来说是一致的。

func swapTwoValues<T>(inout a: T, inout b: T) {
    let temporaryA = a
    a = b
    b = temporaryA
}
Run Code Online (Sandbox Code Playgroud)

如果在参数 a 的情况下 T 是 Int,那么在参数 b 的情况下 T 也必须是 Int。正如该函数的使用所示:

var valueA = 2
var valueB = 4
swapTwoValues(&valueA, b: &valueB)

valueA // 4
valueB // 2
Run Code Online (Sandbox Code Playgroud)

例如,我们无法将 String 替换为 Int,甚至无法将 Int 替换为 Double,但只要类型相同,那么此泛型方法将采用任何类型,因为它在所有其他方面都不受限制。

var valueA = "Hello"
var valueB = "Swift"
swapTwoValues(&valueA, b: &valueB)

valueA // "Swift"
valueB // "Hello"
Run Code Online (Sandbox Code Playgroud)

然而,这并不意味着多种类型被排除在泛型函数之外。您只需分配一个不同的字母来表示不同的类型(使用的字母无关紧要,仅使用 T,因为它是 Type 的第一个字母,但没有理由不能将其替换为 Q 或任何其他类型)其他信件):

func swapTwoValues<T,S>(inout a: T, inout b: T, inout c: S, inout d: S) {
    let temporaryA = a
    a = b
    b = temporaryA

    let temporaryC = c
    c = d
    d = temporaryC
}

var valueA = 2
var valueB = 4

var valueC = "Hello"
var valueD = "Swift"
swapTwoValues(&valueA, b: &valueB, c:&valueC, d:&valueD)

valueA  // 4
valueB // 2

valueC // "Swift"
valueD // "Hello"
Run Code Online (Sandbox Code Playgroud)

注意:我们仍然不能将 T 换成 S,因为 Swift 是一种强类型语言,我们无法保证它们是相同的。

当涉及协议来约束泛型类型时,它会变得更有趣。这里我使用 UnsignedIntegerType 来实现:

func swapTwoValues<T: UnsignedIntegerType>(inout a: T, inout b: T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var valueA:UInt = 10
var valueB:UInt = 11

swapTwoValues(&valueA, b: &valueB)
Run Code Online (Sandbox Code Playgroud)

现在只有 UInt、UInt8、UInt32 等类型是可接受的,所有其他值都将被拒绝并创建错误。

注意:使用协议来约束类型的原因是为了保证某些方法能够工作。例如,如果需要通用函数来创建新类型实例,那么它必须采用带有 init 方法的协议。(您可以在 Apple 文档中查看每种类型的协议采用情况。)

我们可以更进一步,使用where关键字来确定泛型集合中包含的类型:

func swapTwoValues<T: CollectionType where T.Generator.Element: UnsignedIntegerType>(inout a: T, inout b: T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var valueA:[UInt] = [10,12,4]
var valueB:[UInt] = [11,45,67]

swapTwoValues(&valueA, b: &valueB)

valueA  // [11, 45, 67]
valueB // [10, 12, 4]
Run Code Online (Sandbox Code Playgroud)

或者执行诸如检查第二种类型是否等于集合中元素的类型之类的操作==

func swapTwoValues<T: CollectionType, S where S == T.Generator.Element>(inout a: T, inout b: T, inout c: S, inout d: S) {
    let temporaryA = a
    a = b
    b = temporaryA

    let temporaryC = c
    c =  d
    d = temporaryC
}
Run Code Online (Sandbox Code Playgroud)

进一步阅读: Swift 2 中的协议扩展让事情变得更加有趣,因为现在泛型函数可以呈现 Type 方法的特征,这使得它们更容易被发现。