swift-泛型与集合

一、认识泛型

1.1 泛型的基本写法

首先我们需要指定一个占位符T,紧挨着写在函数名后面的一对尖括号表示T遵循的协议,其次我们用T来替换任意定义的函数形式参数。

func multiNumInt(x:Int,y:Int)->Int{
    return x*y
}
func multiNumInt<T:FloatingPoint>(x:T,y:T)->T{
    return x*y
}

如果一个栈可以实现任意数据结构的存储,那么这个栈用泛型怎么定义呢?我们先看看正常的栈是怎么定义的

struct Stack{
    var items = [Int]()
    mutating func push(_ item: Int){
        items.append(item)
    }
    mutating func pop()->Int?{
        if items.isEmpty{
            return nil
        }
        return items.removeLast()
    }
    
}

接下来我们定义一个协议栈:

struct Stack<T>{
    var items = [T]()
    mutating func push(_ item: T){
        items.append(item)
    }
    mutating func pop()->T?{
        if items.isEmpty{
            return nil
        }
        return items.removeLast()
    }
    
}

1.2 协议的泛型

我们首先将上面的栈的相同行为定义为一个协议

protocol StackProtocol{
    var itemCount: Int{get}
    mutating func push() -> Int
    mutating func pop() -> Int?
    func index(of index: Int) -> Int
}

我们试试是不是可以将协议也定义为泛型?

 

 

 我们通过验证发现,协议是不能定义为泛型的,要使用关联对象,才可以使用

 

 

 那关联类型是否可以添加约束呢?答案是肯定的

protocol StackProtocol{
    associatedtype T:FixedWidthInteger
    var itemCount: Int{get}
    mutating func push() -> Int
    mutating func pop() -> Int?
    func index(of index: Int) -> Int
}

当然,我们也可以在约束中使用协议,我们可以看到Even是一个关联类型,但是他的约束中涉及到了两个,第一个是需要遵守EventProtocol协议,第二个是通过where分句来保证指定的类型形式参数和关联类型必须相同。

protocol EventProtocol:StackProtocol{
    associatedtype Even:EventProtocol where Even.T == T
    func pushEven(item:Int)->Even
}

1.3 类型擦除

首先,我们先来看下面一段代码(场景是需要请求用户数据)

 

 

 我们可以看到程序中报错了,这意味着协议DataFetch只能作泛型约束,不能作为具体约束类型,因为编译器无法确定DataFetch的具体类型是什么,那么我们可以改成userdata

protocol DataFetch{
    associatedtype dataType
    func fetch(completion:((Result<dataType,Error>)->Void)?)
}
struct User{
    let userID:Int
    let name:String
}
struct userData:DataFetch{
    typealias dataType = User
    func fetch(completion: ((Result<User, Error>) -> Void)?) {
        let user = User(userID: 11, name: "swift")
        completion?(.success(user))
    }
}
//我们通过userdata来拿到user数据
class someViewController{
    let userData:userData
    init(userData:userData){
        self.userData = userData
    }
}

这样来看确实是没有问题的,但是这样someViewController和UserData之间的耦合性就严重了,此时我们可以通过引入一个中间层的方式来解决

protocol DataFetch{
    associatedtype dataType
    func fetch(completion:((Result<dataType,Error>)->Void)?)
}
struct User{
    let userID:Int
    let name:String
}
//引入中间层来解决
struct AnyDataFetch<T>:DataFetch{
    typealias dataType = T
    let _fetch:(((Result<dataType,Error>)->Void)?)->Void
    init <U:DataFetch>(_fetchable:U) where U.dataType == T{
        //需要实现的类型在这里注入
        _fetch = _fetchable.fetch
    }
    func fetch(completion: ((Result<T, Error>) -> Void)?) {
        //转发协议的抽象类型
        _fetch(completion)
    }
}
struct userData:DataFetch{
    typealias dataType = User
    func fetch(completion: ((Result<User, Error>) -> Void)?) {
        let user = User(userID: 11, name: "swift")
        completion?(.success(user))
    }
}
struct VIPData:DataFetch{
    typealias dataType = User
    func fetch(completion: ((Result<User, Error>) -> Void)?) {
        let user = User(userID: 11, name: "VIP")
        completion?(.success(user))
}
}
//我们通过userdata来拿到user数据
class someViewController{
    let userData:AnyDataFetch<User>
    init(userData:AnyDataFetch<User>){
        self.userData = userData
    }
}
let vipUser = VIPData()
let anyUser = AnyDataFetch<User>(_fetchable: vipUser)
//此时的VC就可以穿入不同的user类型,不需要关心具体类型
let vc = someViewController.init(userData: anyUser)
  • 在这里,我们定义了一个中间层结构AnyDataFetch,他实现了DataFetch的所有方法
  • 在AnyDataFetch的初始化过程中,实现协议的类型会被当作参数传入
  • 在AnyDataFetch实现的具体协议方法Fetch中,再转发实现协议的抽象类型
  • 这时候,AnyDataFetch就是一个具体类型,而非泛型,即完成了类型擦除

二、泛型原理

泛型相当于是用T提前占据了内存位置,那么泛型是通过什么来计算传入的类型以及大小的呢?

struct ValueWitnessTable {
    var initializeBufferWithCopyOfBuffer:UnsafeRawPointer
    var destroy:UnsafeRawPointer
    var initializeWithCopy:UnsafeRawPointer
    var assignWithCopy:UnsafeRawPointer
    var initializeWithTake:UnsafeRawPointer
    var assignWithTake:UnsafeRawPointer
    var getEnumTagSinglePayload:UnsafeRawPointer
    var storeEnumTagSinglePayload:UnsafeRawPointer
    var size:Int
    var stride:Int
    var flags:Int
    var targrtMetadata:TargetMetadata
}

泛型通过 valueWItnessable来管理内存,我们可以还原出 valueWItnessable

三、Swift集合

3.1 Sequence协议

Sequence协议表达的可以是一个有限的集合,也可以是一个无限的集合,而且他只提供集合中的元素以及如访问元素的接口,关系如下所示:

 

 

 在研究Sequence之前,我们先从一些简单的代码入手:

let numbers = [1,2,3,4,5]
for number in numbers{
    print(number)
}

这是一个非常常见的for循环,但是我们需要思考一个问题,在for循环的底层是如何进行遍历的?我们通过sil源码来观察一下

 

 

 我们不难看出,for循环主要调用的是.next()方法

 

 

 

 

 

 

 for in本质上是个语法糖,通过Sequence创建一个迭代器,然后把当前数组传给迭代器,最后调用迭代器的next方法将数组的元素遍历出来

3.2 Sequence

接下来,我们自定义一个遵从Sequence的迭代器

  • 有限的集合
struct LGSequence:Sequence{
    typealias Element = Int
    var arrayCount:Int
    //对于sequence来说,需要创建一个迭代器,而对于迭代器来说遍历当前集合中的元素 所以我们需要提供一个遍历的迭代器
 func makeIterator() -> LGIterator {
     return LGIterator(_sequence: self)
    }
}
//迭代器接受一个Sequence类型返回 通过next方法将元素返回
struct LGIterator:IteratorProtocol{
    typealias Element = Int
    let sequence:LGSequence
    init(_sequence:LGSequence) {
        self.sequence = _sequence
    }
    var count = 0
    mutating func next() -> Element? {
        guard count < sequence.arrayCount else{
            return nil
        }
        count += 1
        return count
    }
}
var s = LGIterator(_sequence: LGSequence(arrayCount: 10))
while let x = s.next(){
    print(x)
}
// 1 2 3 4 5 6 7 8 9 10
  • 无限的集合
struct unlimitedIterator:IteratorProtocol{
    typealias Element = Int
    let value:Int
    func next() -> Element? {
        return value
    }
}
var iterator = unlimitedIterator(value: 10)
while let x = iterator.next(){
    print(x)
}
// 10 10 10 ....

3.3 Collection协议

Swift中的Collection协议是建立在Sequence协议之上的,为有限的序列提供下标访问的能力,同时增加了count属性,自定义索引的特性

  • 以环形数组为例
extension FixedWidthInteger {
    /// Returns the next power of two.
    @inlinable
    func nextPowerOf2() -> Self {
        guard self != 0 else {
            return 1
        }
        //
        return 1 << (Self.bitWidth - (self - 1).leadingZeroBitCount)
    }
}

struct RingBuffer<Element>{
    //internal只能访问自己模块的任何internal实体,不能访问其他模块中的internal实体
    //ContiguousArray相当于swift自己的array,比oc的效率要高
    //headIndex相当于头指针
    //tailindex相当于尾指针
    internal var _buffer: ContiguousArray<Element?>
    internal var headIndex: Int = 0
    internal var tailIndex: Int = 0

    internal var mask: Int{
        return self._buffer.count - 1
    }

    init(initalCapacity: Int) {
        //nextPowerOf2 == 2的n次
        let capcatiy = initalCapacity.nextPowerOf2()

        self._buffer = ContiguousArray<Element?>.init(repeating: nil, count:capcatiy)
    }
   //移动尾指针
    mutating func advancedTailIndex(by: Int){
        self.tailIndex = self.indexAdvanced(index: self.tailIndex, by: by)
    }
    //移动头指针
    mutating func advancedHeadIndex(by: Int){
        self.headIndex = self.indexAdvanced(index: self.headIndex, by: by)
    }

    func indexAdvanced(index: Int, by: Int) -> Int{
        return (index + by) & self.mask
    }


    mutating func append(_ value: Element){
        _buffer[self.tailIndex] = value
        self.advancedTailIndex(by: 1)

        if self.tailIndex == self.headIndex {
            fatalError("out of bounds")
        }
    }

    mutating func read() -> Element?{
        let element = _buffer[self.headIndex]
        self.advancedHeadIndex(by: 1)
        return element
    }
}
  • MutableCollection 允许集合通过下标修改自身元素
extension RingBuffer: Collection, MutableCollection{
    var startIndex: Int{
        return self.headIndex
    }

    var endIndex: Int{
        return self.tailIndex
    }

    subscript(position: Int) -> Element? {
        get{
            //获取值
            return self._buffer[position]
        }
        set{
            //通过下标修改值
            self._buffer[position] = newValue
        }
    }
//移动当前索引的位置
    func index(after i: Int) -> Int {
        return (i + 1) & self.mask
    }
}
  • RangeReplaceCollection 允许集合修改任意区间元素
extension RingBuffer:RangeReplaceableCollection{
    init() {
        self.init(initalCapacity: 10)
    }
    //移除元素
    mutating func remove(at position: Int) -> Element? {
        var currentIndex = position
        let element = self._buffer[position]
        
        switch position{
            //当要删除的结点和头结点重合时,直接头结点右移动一位
        case self.headIndex:
            self.advancedHeadIndex(by: 1)
            self._buffer = nil
        default:
            self._buffer[position] = nil
            var nextIndex = self.indexAdvanced(index: position, by: 1)
            while nextIndex != self.tailIndex{
                self._buffer.swapAt(currentIndex, nextIndex)
                currentIndex - nextIndex
                nextIndex = self.indexAdvanced(index: currentIndex, by: 1)
            }
            self.advancedHeadIndex(by: -1)
        }
        return element
    }
}
  • BidirectionalCollection 可以向前或者向后遍历元素

extension RingBuffer: BidirectionalCollection{
    func index(before i: Int) -> Int {
        return (i - 1) & self.mask
    }
}
  • RandomAccessCollection 可以任意访问集合元素

extension RingBuffer: RandomAccessCollection{
      func index(_ i: Int, offsetBy distance: Int) -> Int {
        return (i + distance) & self.mask
      }



      func distance(from start: Int, to end: Int) -> Int {
        return end - start
      }
}

 

posted on 2022-02-17 19:57  suanningmeng98  阅读(103)  评论(0编辑  收藏  举报