Swift学习(九)泛型、关联类型

663 阅读3分钟

泛型程序设计(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。Ada、Delphi、EiffelJavaC#F#Swift 和 Visual Basic .NET 称之为泛型(generics);ML、Scala 和 Haskell称之为参数多态(parametric polymorphism);C++ 和 D称之为模板。具有广泛影响的1994年版的《Design Patterns》一书称之为参数化类型(parameterized type)。 (来自百度百科)

泛型型的基本用法

泛型的使用范围:struct、class、enum、func。

struct OSStack<T> {
    var stackContent: [T]
    
    //出栈
    mutating func pop() -> T? {
        if stackContent.isEmpty {return nil}
        return stackContent.removeLast()
    }
    
    mutating func push(_ item: T) {
        stackContent.append(item)
    }
}
class OSGenericityClass<T> {
    var a: T
    init(_ a: T){
        self.a = a
    }
}
enum OSGenericityEnum<T> {
    case error
    case reseponse(data: T)
}

func testGenricity<T>(_ value: T) -> T{
        let temp = value
        return value
    }

泛型函数内存分配

在上面泛型在函数里面的使用中,在编译的过程中,因为temp的类型是不确定的,那么系统会如何给temp分配内存呢?这是这一小节要解释的内容。

首先来看一下valueWitnessTablemetadata的存储关系。

image.png

可以得到以下的内存结构图: image.png 可以看到我们先获取mateData,然后地址往后移动8个字节就可以取到对应的valueWitnessTable,而这个valueWitnessTable中存储了所需内存的大小(size)。此时我们就可以找到大致的答案了,因为泛型传递的时候传递的根本应该是MateData,系统有了MateData就可以找对对应的valueWitnessTable,取出其中的size。

//值类型的VWT存储

    func func1() {
        var structType = OSBed.self
        let ptr = unsafeBitCast(structType as Any.Type, to: UnsafeMutablePointer<TargetMetadata>.self)
        let valueWitnessTable = UnsafeRawPointer(ptr).advanced(by: -MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: UnsafeMutablePointer<ValueWitnessTable>.self).pointee
        print(valueWitnessTable.pointee.size)
    }
//引用类型的VWT
//也可以使用上面的方法,这种取法和内存结构图对应。

    func func11() {
        var room = OSRoom("001", "111")
        //获取实力对象的指针
        let objectRowPtr = Unmanaged.passUnretained(room as AnyObject).toOpaque()
        //绑定指针(类型转化)
        let objPtr = objectRowPtr.bindMemory(to: OSRoomHeap.self, capacity: 1)
        let vwtPtr = objPtr.pointee.matedata.advanced(by: -MemoryLayout<UnsafeRawPointer>.size) .assumingMemoryBound(to: UnsafeMutablePointer<ValueWitnessTable>.self).pointee
        print(vwtPtr.pointee.size)
 }
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: UInt32
    var extraInhabitantCount: UInt32
}

关联类型

在swift中,协议是不可以使用泛型的。如下图,编译器提示使用 associated types代替generic

image.png

protocol OSStackProtocol {
    //定义一个关联类型
    associatedtype T
    var stackContent: [T] {get}
    mutating func pop() -> T?
    mutating func push(_ item: T)
}

遵循该协议的时候需要指明关联类型。

struct OSStackProtocolOne:OSStackProtocol {
    //指明关联类型
    typealias T = Int

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

也可以和泛型一起使用:

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

类型擦除

有时你想对外部调用者隐藏某个类的具体类型,或是一些实现细节。在一些情况下,这样做能防止静态类型在项目中滥用,或者保证了类型间的交互。类型擦除就是移除某个类的具体类型使其变得更通用的过程。

我们通过自己实现AnySequence来理解这个类型擦除。

func func2() {
        func printInts(_ seq: MAnySequence<Int>) {
                for elt in seq {
                    print(elt)
                }
            }
        let array = [1, 2, 3, 4, 5]
        printInts(MAnySequence.make(array))
        printInts(MAnySequence.make(array[1 ..< 4]))
    }
class MAnySequence<U>: Sequence {
    __consuming func makeIterator() -> MIterator {
        fatalError("Must override makeIterator()")
    }
    
    typealias Iterator = MIterator
    
    
    class MIterator: IteratorProtocol {
        typealias Element = U
        
        func next() -> U? {
            
                    fatalError("Must override next()")
        }
        
    }
}


private class MAnySequenceImpl<Seq: Sequence>: MAnySequence<Seq.Element> {
    class IteratorImpl: MIterator {
        var wrapped: Seq.Iterator
        
        init(_ wrapped: Seq.Iterator) {
            self.wrapped = wrapped
        }
        
        override func next() -> Seq.Element? {
            return wrapped.next()
        }
    }
    
    var seq: Seq

    init(_ seq: Seq) {
        self.seq = seq
    }
    
    override func makeIterator() -> MIterator {
        return IteratorImpl(seq.makeIterator())
    }
    
    
    
}

extension MAnySequence {
    static func make<Seq: Sequence>(_ seq: Seq) -> MAnySequence<Element> where Seq.Element == Element {
        return MAnySequenceImpl<Seq>(seq)
    }
}

参考