likes
comments
collection
share

🐻Swift 泛型解析

作者站长头像
站长
· 阅读数 31

一、泛型

泛型,可以让我们在用相同的函数处理不同的数据类型.

如交换两个变量的值,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)
        }
    }
}

github.com/Tliens/Spee…

我们就可以更方便的使用UserDefaults了。

八、总结

  • 泛型通俗的将就是占位,具体类型可以延后
  • 利用这特性,使得我们可以在类、结构体、协议中能够针对进行设计,从而暂时忽略具体类型
  • 我们可以制作泛型类型,例如栈对象
  • 如果类、结构体、协议中有多个泛型,而且还会在不同的函数中使用,我们通常使用关联对象定义泛型,从而在整个类、结构体、协议中进行使用,达到公用的目的
  • 函数使用时可以对泛型进行约束
  • where可以用来对泛型进一步进行约束

九、参考链接

转载自:https://juejin.cn/post/7000916678150193159
评论
请登录