swift-- 泛型

2020-12-29  本文已影响0人  Mjs

类型约束

在⼀个类型参数后⾯放置协议或者是类,⽐如就要求我们的类型参数 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。

总结:

泛型的⽅法调⽤


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)
上一篇下一篇

猜你喜欢

热点阅读