4

🐻Swift 泛型解析

 3 years ago
source link: https://juejin.cn/post/7000916678150193159/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
2021年08月27日 阅读 320

🐻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)
        }
    }
}
复制代码

github.com/Tliens/Spee…

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

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

九、参考链接


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK