美文网首页
swift-- 泛型

swift-- 泛型

作者: Mjs | 来源:发表于2020-12-29 10:33 被阅读0次

    类型约束

    在⼀个类型参数后⾯放置协议或者是类,⽐如就要求我们的类型参数 T 遵循 Equatable 协议

    func test<T: Equatable>(_ a: T ,_ b: T) -> Bool{ 
     return a == b 
     }
    

    关联类型

    在定义协议的时候,使⽤关联类型给协议中⽤到的类型起⼀个占位符名称。

    protocol StackProtocol { 
     associatedtype Item 
     }
    
    struct Stack: StackProtocol{ 
     typealias Item = Int 
     private var items = [Item]() 
     mutating func push(_ item: Item){ 
     items.append(item) 
     }
    

    Where语句

    添加限制条件

     protocol StackProtocol {
        associatedtype Item
        var itemCount: Int{ get }
        mutating func pop() -> Item?
        func index(of index: Int) -> Item
    }
    struct Stack: StackProtocol{
        typealias Item = Int
        private var items = [Item]()
        var itemCount: Int{
            get{
                return items.count
            }
        }
        mutating func push(_ item: Item){
            items.append(item)
        }
        mutating func pop() -> Item?{
    
        if items.isEmpty { return nil }
            return items.removeLast()
        }
        func index(of index: Int) -> Item {
            return items[index]
        }
    }
    func compare<T1: StackProtocol, T2: StackProtocol>(_ stack1: T1, _ stack2: T2)-> Bool where T1.Item == T2.Item, T1.Item: Equatable {
        guard stack1.itemCount == stack2.itemCount else {
            return false
        }
        for i in 0..<stack1.itemCount {
            if stack1.index(of: i) != stack2.index(of: i) {
                return false
            }
        }
        return true
    }
    
    

    有时候我们希望在当前泛型制定类型的时候拥有特定功能

    extension StackProtocol where Item == Int{ 
     func test(){ 
     print("test") 
     } 
     }
    

    泛型函数

    class Teacher{}
    
    func testGen<T>(_ value: T)->T{
        let tmp = value
        return value
    }
    testGen(10)
    testGen((10,20))
    testGen(Teacher())
    
    

    查看IR

    
    define hidden swiftcc void @"$s4main7testGenyxxlF"(%swift.opaque* noalias nocapture sret, %swift.opaque* noalias nocapture, %swift.type* %T) #0 {
    entry:
      %T1 = alloca %swift.type*, align 8
      %tmp.debug = alloca i8*, align 8
      %2 = bitcast i8** %tmp.debug to i8*
      call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
      store %swift.type* %T, %swift.type** %T1, align 8
      %3 = bitcast %swift.type* %T to i8***
      %4 = getelementptr inbounds i8**, i8*** %3, i64 -1
    //从当前Metadata中拿到valueWitnesses,index = 0 是Kind
      %T.valueWitnesses = load i8**, i8*** %4, align 8, !invariant.load !42, !dereferenceable !43
    //做一个类型的转换
      %5 = bitcast i8** %T.valueWitnesses to %swift.vwtable*
    //在valueWitnesses中拿到当前的这个类型的size大小
      %6 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %5, i32 0, i32 8
      %size = load i64, i64* %6, align 8, !invariant.load !42
    //根据拿到的size大小来分配内存空间
      %7 = alloca i8, i64 %size, align 16
      call void @llvm.lifetime.start.p0i8(i64 -1, i8* %7)
      %8 = bitcast i8* %7 to %swift.opaque*
    //初始化tmp的内存空间
      store i8* %7, i8** %tmp.debug, align 8
      %9 = getelementptr inbounds i8*, i8** %T.valueWitnesses, i32 2
      %10 = load i8*, i8** %9, align 8, !invariant.load !42
    //copy
      %initializeWithCopy = bitcast i8* %10 to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
      %11 = call %swift.opaque* %initializeWithCopy(%swift.opaque* noalias %8, %swift.opaque* noalias %1, %swift.type* %T) #5
      %12 = call %swift.opaque* %initializeWithCopy(%swift.opaque* noalias %0, %swift.opaque* noalias %1, %swift.type* %T) #5
      %13 = getelementptr inbounds i8*, i8** %T.valueWitnesses, i32 1
      %14 = load i8*, i8** %13, align 8, !invariant.load !42
    //destroy
      %destroy = bitcast i8* %14 to void (%swift.opaque*, %swift.type*)*
      call void %destroy(%swift.opaque* noalias %8, %swift.type* %T) #5
      %15 = bitcast %swift.opaque* %8 to i8*
      call void @llvm.lifetime.end.p0i8(i64 -1, i8* %15)
      ret void
    }
    
    

    valueWitnesses: 值目击表
    泛型类型使⽤ VWT 进⾏内存管理,VWT 由编译器⽣成,其存储了该类型的 size、aligment(对⻬⽅ 式)以及针对该类型的基本内存操作。

    当对泛型类型进⾏内存操作(如:内存拷⻉)时,最终会调⽤对应泛型类型的 VWT 中的基本内存操作。 泛型类型不同,其对应的 VWT 也不同。下图所示为⼀个⼩的值类型和⼀个引⽤类型的 VWT。

    总结:

    • 对于⼀个值类型,如:integer。该类型的 copy 和 move 操作会进⾏内存拷⻉;destroy 操作则不进 ⾏任何操作。
    • 对于⼀个引⽤类型,如:class。该类型的 copy 操作会对引⽤计数加 1;move 操作会拷⻉指针,⽽不 会更新引⽤计数;destroy 操作会对引⽤计数减 1

    泛型的⽅法调⽤

    
    func makeIncrement() -> (Int) -> Int{
        var  runningTotal = 10
        return {
            runningTotal += $0
            return runningTotal
        }
    }
    
    func testGen<T>(_ value: T){
    
    }
    
    //{i8 * , swift type *}
    let m = makeIncrement()
    
    testGen(m)
    

    查看IR

    define i32 @main(i32, i8**) #0 {
    entry:
      %2 = alloca %swift.function, align 8
      %3 = bitcast i8** %1 to i8*
      %4 = call swiftcc { i8*, %swift.refcounted* } @"$s4main13makeIncrementS2icyF"()
      %5 = extractvalue { i8*, %swift.refcounted* } %4, 0//闭包表达式的地址
      %6 = extractvalue { i8*, %swift.refcounted* } %4, 1//捕获值的地址
    //把值存放f这个变量中,并转换成指针
      store i8* %5, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s4main1myS2icvp", i32 0, i32 0), align 8
      store %swift.refcounted* %6, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s4main1myS2icvp", i32 0, i32 1), align 8
      %7 = bitcast %swift.function* %2 to i8*
      call void @llvm.lifetime.start.p0i8(i64 16, i8* %7)
      %8 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s4main1myS2icvp", i32 0, i32 0), align 8
      %9 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s4main1myS2icvp", i32 0, i32 1), align 8
      %10 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %9) #2
    //创建一个结构体
      %11 = call noalias %swift.refcounted* @swift_allocObject(%swift.type* getelementptr inbounds (%swift.full_boxmetadata, %swift.full_boxmetadata* @metadata, i32 0, i32 2), i64 32, i64 7) #2
      %12 = bitcast %swift.refcounted* %11 to <{ %swift.refcounted, %swift.function }>*
      %13 = getelementptr inbounds <{ %swift.refcounted, %swift.function }>, <{ %swift.refcounted, %swift.function }>* %12, i32 0, i32 1
      %.fn = getelementptr inbounds %swift.function, %swift.function* %13, i32 0, i32 0
      store i8* %8, i8** %.fn, align 8
      %.data = getelementptr inbounds %swift.function, %swift.function* %13, i32 0, i32 1
      store %swift.refcounted* %9, %swift.refcounted** %.data, align 8
      %.fn1 = getelementptr inbounds %swift.function, %swift.function* %2, i32 0, i32 0
      store i8* bitcast (void (%TSi*, %TSi*, %swift.refcounted*)* @"$sS2iIegyd_S2iIegnr_TRTA" to i8*), i8** %.fn1, align 8
      %.data2 = getelementptr inbounds %swift.function, %swift.function* %2, i32 0, i32 1
      store %swift.refcounted* %11, %swift.refcounted** %.data2, align 8
      %14 = bitcast %swift.function* %2 to %swift.opaque*
      %15 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$sS2icMD") #4
      call swiftcc void @"$s4main7testGenyyxlF"(%swift.opaque* noalias nocapture %14, %swift.type* %15)
      %.data3 = getelementptr inbounds %swift.function, %swift.function* %2, i32 0, i32 1
      %16 = load %swift.refcounted*, %swift.refcounted** %.data3, align 8
      call void @swift_release(%swift.refcounted* %16) #2
      %17 = bitcast %swift.function* %2 to i8*
      call void @llvm.lifetime.end.p0i8(i64 16, i8* %17)
      ret i32 0
    }
    
    
    struct FuntionData<T>{
        var ptr: UnsafeRawPointer //
        var captureValue: UnsafePointer<T>?
    }
    
    struct Box<T> {
        var refCounted: HeapObject
        var value: T
    }
    
    struct GenData<T>{
        var ref: HeapObject
        var function: FuntionData<T>
    }
    
    func makeIncrement() -> (Int) -> Int{
        var  runningTotal = 10
        return {
            runningTotal += $0
            return runningTotal
        }
    }
    
    func testGen<T>(_ value: T){
        let ptr = UnsafeMutablePointer<T>.allocate(capacity: 1)
        ptr.initialize(to: value)
    
        let ctx = ptr.withMemoryRebound(to: FuntionData<GenData<Box<Int>>>.self, capacity: 1) {
            $0.pointee.captureValue?.pointee.function.captureValue!
        }
    
        print(ctx?.pointee.value)
    }
    ·············
    Optional(10)
    

    相关文章

      网友评论

          本文标题:swift-- 泛型

          本文链接:https://www.haomeiwen.com/subject/kajtoktx.html