🐻Swift 泛型解析
一、泛型
泛型,可以让我们在用相同的函数处理不同的数据类型.
如交换两个变量的值,T就是泛型.
简而言之,泛型就只一种占位,提前把位置占了,具体的类型,延后指定。
func swapTwoValues<T>(_ a: inout T, _ b: inout T)
我们交换时指定类型就可以,如:Int\String\Double等等
二、泛型类型
类中的泛型类型如何定义?
示例代码:
struct Stack<Element> {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
Element 就是泛型,这样我们完成一个简单地、不计较类型的栈,可以存放Int、Double等任意类型
三、泛型类型扩展
extension Stack {
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
可以直接扩展泛型类型,并且Element具体类型可以省略,直接使用
四、类型约束
类型约束指定了参数必须遵循某项协议或者继承某个类,可以缩窄函数的使用范围。
protocol PName{}
class Person:PName{}
class Animail:PName{}
func someFunction<T: PName, U: PName>(x1: T, x2: U) {
}
其中PName指的就是类型约束,意味着T、U都必须是遵守PName协议的。
PName,也可以换成某种类型,如:String、Int等
where
可以进一步对函数进行约束,函数只对这中约束成立的参数才能够使用
func someFunction<T: PName, U: PName>(x1: T, x2: U) where x1:UIView {
}
上面这个函数,又在原来的基础上,对参数做了限制,要求 x1 继承UIView。
同样,我们也可以对关联类型进行约束
protocol PNewName{
associatedtype Item: PName where Item:UIView
}
where 对类型进行扩展
我们扩展上述的栈结构,Element 需要遵循Equatable 方可使用
extension Stack where Element: Equatable {
func isTop(_ item: Element) -> Bool {
guard let topItem = items.last else {
return false
}
return topItem == item
}
}
如果尝试在其元素不符合 Equatable 协议的栈上调用 isTop(_:) 方法,则会收到编译时错误
五、关联类型
associatedtype
用于协议中使用,可以让具体类型在使用的时候再确定。
也就是遵循协议的对象确定关联类型的实际类型
示例: 老虎和山羊都有吃的能力,但老虎吃肉、山羊吃草。
利用泛型协议我们实现了多态
protocol Eatable{
associatedtype Item
func eat(_ kind:Item)
}
class Tiger:Eatable{
func eat(_ kind:Meet){
}
}
class Sheep:Eatable{
func eat(_ kind:Grass){
}
}
struct Meet{
}
struct Grass{
}
如果采用面向协议编程的思想可以这么干.尤其是关联类型比较复杂时.
六、不透明类型 some
func get(_ type:Int) -> some Codable{
}
这个函数要求,必须返回一个遵循Codable的结果。
some 还可以用在属性上
var person: some Codable
测试发现 some 可以省略。
七、泛型 + 属性包裹器
泛型配合Swift的其他特性,可以擦除很多火花。
@propertyWrapper
public struct SSDefault<T> {
public let key: String
public let defaultValue: T
init(_ key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
public var wrappedValue: T {
get {
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
}
我们就可以更方便的使用UserDefaults了。
八、总结
- 泛型通俗的将就是占位,具体类型可以延后
- 利用这特性,使得我们可以在类、结构体、协议中能够针对进行设计,从而暂时忽略具体类型
- 我们可以制作泛型类型,例如栈对象
- 如果类、结构体、协议中有多个泛型,而且还会在不同的函数中使用,我们通常使用关联对象定义泛型,从而在整个类、结构体、协议中进行使用,达到公用的目的
- 函数使用时可以对泛型进行约束
- where可以用来对泛型进一步进行约束
九、参考链接
转载自:https://juejin.cn/post/7000916678150193159