31、swift开发iOS——泛型

Swift 泛型

Swift 提供了泛型让你写出灵活且可重用的函数和类型。

Swift 标准库是通过泛型代码构建出来的。

Swift 的数组和字典类型都是泛型集。

你可以创建一个Int数组,也可创建一个String数组,或者甚至于可以是任何其他 Swift 的类型数据数组。

以下实例是一个非泛型函数 exchange 用来交换两个 Int 值:

// 定义一个交换两个变量的函数

func exchange( a: inout Int, b: inout Int) {

    let temp = a

    a = b

    b = temp

}


var numb1 = 100

var numb2 = 200


print("交换前数据: \(numb1) 和 \(numb2)")

exchange(a: &numb1, b: &numb2)

print("交换后数据: \(numb1) 和 \(numb2)")

以上程序执行输出结果为:

交换前数据: 100 和 200

交换后数据: 200 和 100

泛型函数可以访问任何类型,如 Int 或 String。

以下实例是一个泛型函数 exchange 用来交换两个 Int 和 String 值:

func exchange<T>(inout a: T, inout b: T) {

    let temp = a

    a = b

    b = temp

}


var numb1 = 100

var numb2 = 200


print("交换前数据:  \(numb1) 和 \(numb2)")

exchange(&numb1, b: &numb2)

print("交换后数据: \(numb1) 和 \(numb2)")


var str1 = "A"

var str2 = "B"


print("交换前数据:  \(str1) 和 \(str2)")

exchange(&str1, b: &str2)

print("交换后数据: \(str1) 和 \(str2)")

以上程序执行输出结果为:

交换前数据:  100 和 200

交换后数据: 200 和 100

交换前数据:  A 和 B

交换后数据: B 和 A

这个函数的泛型版本使用了占位类型名字(通常此情况下用字母T来表示)来代替实际类型名(如Int、String或Double)。占位类型名没有提示T必须是什么类型,但是它提示了a和b必须是同一类型T,而不管T表示什么类型。只有 exchange(_:_:)函数在每次调用时所传入的实际类型才能决定T所代表的类型。

另外一个不同之处在于这个泛型函数名后面跟着的占位类型名字(T)是用尖括号括起来的()。这个尖括号告诉 Swift 那个T是 exchange(_:_:)函数所定义的一个类型。因为T是一个占位命名类型,Swift 不会去查找命名为T的实际类型。

泛型类型

Swift 允许你定义你自己的泛型类型。

自定义类、结构体和枚举作用于任何类型,如同Array和Dictionary的用法。

struct TOS<T> {

    var items = [T]()

    mutating func push(item: T) {

        items.append(item)

    }

    

    mutating func pop() -> T {

        return items.removeLast()

    }

}


var tos = TOS<String>()

tos.push(item: "Swift")

print(tos.items)


tos.push(item: "泛型")

print(tos.items)


tos.push(item: "类型参数")

print(tos.items)


tos.push(item: "类型参数名")

print(tos.items)



let deletetos = tos.pop()

以上程序执行输出结果为:

["Swift"]

["Swift", "泛型"]

["Swift", "泛型", "类型参数"]

["Swift", "泛型", "类型参数", "类型参数名"]

扩展泛型类型

当你扩展一个泛型类型的时候(使用 extension 关键字),你并不需要在扩展的定义中提供类型参数列表。更加方便的是,原始类型定义中声明的类型参数列表在扩展里是可以使用的,并且这些来自原始类型中的参数名称会被用作原始定义中类型参数的引用。

实例

下面的例子扩展了泛型 TOS 类型,为其添加了一个名为 first 的只读计算属性,它将会返回当前栈顶端的元素而不会将其从栈中移除。

struct TOS<T> {

    var items = [T]()

    mutating func push(item: T) {

        items.append(item)

    }

    

    mutating func pop() -> T {

        return items.removeLast()

    }

}


var tos = TOS<String>()

tos.push(item: "Swift")

print(tos.items)


tos.push(item: "泛型")

print(tos.items)


tos.push(item: "类型参数")

print(tos.items)


tos.push(item: "类型参数名")

print(tos.items)


// 扩展泛型 TOS 类型

extension TOS {

    var first: T? {

        return items.isEmpty ? nil : items[items.count - 1]

    }

}


if let first = tos.first {

    print("栈顶部项:\(first)")

}

以上程序执行输出结果为:

["Swift"]

["Swift", "泛型"]

["Swift", "泛型", "类型参数"]

["Swift", "泛型", "类型参数", "类型参数名"]

栈顶部项:类型参数名

类型约束

类型约束指定了一个必须继承自指定类的类型参数,或者遵循一个特定的协议或协议构成。

类型约束语法

你可以写一个在一个类型参数名后面的类型约束,通过冒号分割,来作为类型参数链的一部分。这种作用于泛型函数的类型约束的基础语法如下所示(和泛型类型的语法相同):

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {

    // 这里是函数主体

}

关联类型实例

Swift 中使用 typealias 关键字来设置关联类型。

定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分是非常有用的。

protocol Container {

    // 定义了一个ItemType关联类型

    associatedtype ItemType

    mutating func append(item: ItemType)

    var count: Int { get }

    subscript(i: Int) -> ItemType { get }

}


// 遵循Container协议的泛型TOS类型

struct TOS<T>: Container {

    // original Stack<T> implementation

    var items = [T]()

    mutating func push(item: T) {

        items.append(item)

    }

    

    mutating func pop() -> T {

        return items.removeLast()

    }

    

    // conformance to the Container protocol

    mutating func append(item: T) {

        self.push(item: item)

    }

    

    var count: Int {

        return items.count

    }

    

    subscript(i: Int) -> T {

        return items[i]

    }

}


var tos = TOS<String>()

tos.push(item: "Swift")

print(tos.items)


tos.push(item: "泛型")

print(tos.items)


tos.push(item: "参数类型")

print(tos.items)


tos.push(item: "类型参数名")

print(tos.items)

以上程序执行输出结果为:

["Swift"]

["Swift", "泛型"]

["Swift", "泛型", "参数类型"]

["Swift", "泛型", "参数类型", "类型参数名"]

Where 语句

类型约束能够确保类型符合泛型函数或类的定义约束。

你可以在参数列表中通过where语句定义参数的约束。

你可以写一个where语句,紧跟在在类型参数列表后面,where语句后跟一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型间的等价(equality)关系。

实例

下面的例子定义了一个名为allItemsMatch的泛型函数,用来检查两个Container实例是否包含相同顺序的相同元素。

如果所有的元素能够匹配,那么返回一个为true的Boolean值,反之则为false。

protocol Container {

    associatedtype ItemType

    mutating func append(item: ItemType)

    var count: Int { get }

    subscript(i: Int) -> ItemType { get }

}


struct Stack<T>: Container {

    // original Stack<T> implementation

    var items = [T]()

    mutating func push(item: T) {

        items.append(item)

    }

    

    mutating func pop() -> T {

        return items.removeLast()

    }

    

    // conformance to the Container protocol

    mutating func append(item: T) {

        self.push(item: item)

    }

    

    var count: Int {

        return items.count

    }

    

    subscript(i: Int) -> T {

        return items[i]

    }

}


func allItemsMatch<

    C1: Container, C2: Container>

    (someContainer: C1, anotherContainer: C2) -> Bool

    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {

    // 检查两个Container的元素个数是否相同

    if someContainer.count != anotherContainer.count {

        return false

    }

    

    // 检查两个Container相应位置的元素彼此是否相等

    for i in 0..<someContainer.count {

        if someContainer[i] != anotherContainer[i] {

            return false

        }

    }

    // 匹配所有项,返回 true

    return true

}


var tos = Stack<String>()

tos.push(item: "Swift")

print(tos.items)


tos.push(item: "泛型")

print(tos.items)


tos.push(item: "Where 语句")

print(tos.items)


var eos = ["Swift", "泛型", "Where 语句"]

print(eos)

以上程序执行输出结果为:

["Swift"]

["Swift", "泛型"]

["Swift", "泛型", "Where 语句"]

["Swift", "泛型", "Where 语句"]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 Swift 中,泛型的 `where` 语句用于限制泛型类型。它可以在定义泛型函数或类型时使用。语法如下: ``` where 泛型别名 : 限制条件 ``` 例如: ``` func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? { for (index, value) in array.enumerated() { if value == valueToFind { return index } } return nil } ``` 在上面的例子中,泛型别名为T,限制条件为T: Equatable,意思是T必须符合Equatable协议 还可以指定多个限制条件 ``` func test<T>(_ value: T) where T: Equatable, T: Hashable { } ``` 这里的限制条件为T: Equatable, T: Hashable,意思是T必须符合Equatable和Hashable协议 ### 回答2: 在Swift中,泛型的where语句用于对泛型进行条件限制,以满足特定需求。使用where语句可以对泛型类型进行约束,使其满足特定的类型要求。 在泛型函数中,我们可以使用where语句来限制泛型参数的类型。例如,我们可以声明一个泛型函数,其中泛型参数必须遵循某个协议或满足某种特定的条件。下面是一个示例: ``` func process<T>(data: T) where T: Equatable { // 在这里操作泛型参数data,比如进行相等比较等操作 } ``` 在上面的示例中,我们限制了泛型参数T必须遵循Equatable协议,即具有相等比较能力。这样,在函数内部就可以使用相等比较操作符进行操作。 除了在泛型函数中使用where语句外,也可以在泛型类型和协议声明中使用where语句对泛型参数进行进一步的限制。例如: ``` protocol Container { associatedtype Item func addItem(item: Item) } struct MyContainer<T>: Container where T: Equatable { typealias Item = T func addItem(item: Item) { // 在这里添加item到容器中 } } ``` 在上面的示例中,我们定义了一个Container协议,其中关联类型Item表示容器中的元素类型。然后,我们通过where语句限制了泛型参数T必须满足Equatable协议,以确保容器中的元素可以进行相等比较。 总结来说,在Swift中,泛型的where语句可以用于泛型函数、泛型类型和协议的声明中,用于对泛型参数进行类型约束和条件限制,以满足特定需求。 ### 回答3: 在Swift中,泛型的where语句用于为泛型类型或泛型函数添加额外的约束。它允许我们在使用泛型时对其类型参数进行更详细的限制。 泛型的where语句可以使用在两个地方:泛型函数和泛型类型。 对于泛型函数,我们可以使用where语句来添加类型约束。例如,我们可以声明一个泛型函数来交换两个变量的值: func swap<T>(a: inout T, b: inout T) where T: Equatable { if a == b { return } let temp = a a = b b = temp } 在上面的代码中,我们使用了where语句来添加了一个类型约束,即T必须遵循Equatable协议。这意味着只有那些可比较相等的类型才能调用这个函数。 对于泛型类型,我们可以使用where语句来添加更多的类型约束。例如,我们可以声明一个泛型结构体,它的关联类型必须遵循特定协议: struct Container<T> where T: CustomStringConvertible { var items: [T] func printItems() { for item in items { print(item.description) } } } 在上面的代码中,我们使用了where语句来添加了一个类型约束,即关联类型T必须遵循CustomStringConvertible协议。这样,我们就可以在printItems方法中使用item的description属性。 总之,泛型的where语句在Swift中用于为泛型类型或泛型函数添加额外的约束。通过使用where语句,我们可以对类型参数进行更详细的限制,以满足特定的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值