swift中泛型的使用

2021-07-16  本文已影响0人  傲骨天成科技

一、函数中使用泛型

比如一个打印字符串的方法:

func myPrintString(str:String){
     print(str)
}

打印出来就直接是字符串类型的

如果我们打印的是一个任意类型的呢?我们可以使用Any试试

// 打印任何东西
func myPrintAny(arg:Any){
     print(any1)
}

使用Any是可以的,但是如果我们有多个参数呢,且要求一致呢?

    func myPrintAny(any1:Any, any2:Any){
        print(any1)
        print(any2)
    }

这样的写法是可以使用任意类型了,但是没有限制住两个参数类型是一样的。导致的结果是对调用此API的人要求特别高,不是我们想要的。

这时泛型就有了用武之地了

    // 打印任何东西
    func myPrint<T>(any1:T, any2:T){
        print(any1)
        print(any2)
    }

从上面的几个事例中可以看出泛型的优势,提升了代码的可复用性、安全性。

泛型和Any的区别?

从表面上看两者没有区别。但是,泛型可以用于定义灵活的函数,类型检查仍然由编译器负责。而Any可以逃避开我们swift的类型系统。因此,可以的话尽量不要使用Any。

二、类中泛型

实现一个数组中的元素可以是任意类型,但是所有元素又必须是同一类型。

//类作用域
class YJKStack<T>: NSObject {
    //栈空间
    private var list:[T] = []
    
    //进栈
    public func push(item:T){
        list.append(item)
    }
    
    //出栈
    public func pop() -> T{
        return list.removeLast()
    }
}

当我们扩展含有泛型的类的时候,泛型是可以直接在扩展中使用的。

extension YJKStack{
    /// 获取栈顶元素
    public func getLast() -> T?{
        return list.last
    }
}

三、泛型类型约束

1.泛型是某个类的子类
class YJKProtocolStack<T: CClass >: NSObject {
    //栈空间
    private var list:[T] = []
    
    //进栈
    public func push(item:T){
        list.append(item)
    }
    
    //出栈
    public func pop() -> T{
        return list.removeLast()
    }
}

class CClass : NSObject {
}
2.泛型必须要实现某个或几个协议
//class YJKProtocolStack<T: A&B>  须实现多个协议的话,用 & 符号链接就好啦。
class YJKProtocolStack<T: A&B>: NSObject {
    //栈空间
    private var list:[T] = []
    
    //进栈
    public func push(item:T){
        list.append(item)
    }
    
    //出栈
    public func pop() -> T{
        return list.removeLast()
    }
}

protocol A {
    
    func myPrintA(item: Int)
}

protocol B {
    
    func myPrintB(item: Int)
}

class ClassAB: NSObject, A, B {
    func myPrintA(item: Int) {
        
        print("我的天神A")
    }
    
    func myPrintB(item: Int) {
        print("我的天神B")
    }
    
    
}


// 使用
var stack:YJKProtocolStack = YJKProtocolStack<ClassAB>.init()

四、结构体中的泛型使用

和类里面的泛型使用是一样的

五、协议中泛型使用需要使用关联类

//一敲出来,编译器就提示你错误啦,并且告诉你怎么写了。
protocol C<T> {

}

//正确的写法就是下面这样的哦
protocol C {
    // Swift 中使用 associatedtype 关键字来设置关联类型实例
    // 具体类型由实现类来决定
    associatedtype ItemType
    
    func itemAtIndex(index:Int) -> ItemType
    
    func myPrint(item:ItemType)
    
    // 局部作用域的泛型和类的写法是一样的。
    func test<T>(a:T)
}

//协议的泛型约束
protocol D {
    associatedtype ItemType:A
}

需要结合使用该协议的类是怎么使用的

//遵循了 C 协议的类
class CClassOne<T>:C{
    
    //要指定 C 协议中, ItemType 的具体类型
    typealias ItemType = T
    
    public var list:[ItemType] = []
    
    //协议方法的实现
    func itemAtIndex(index:Int) -> ItemType{
        return list[index]
    }
    
    func myPrint(item:ItemType){
        
    }
    
    func test<T>(a: T) {
        
    }
}

//实现2
class CClassTwo:C{
    
    typealias ItemType = Int
    
    public var list:[ItemType] = []
    func itemAtIndex(index:Int) -> ItemType{
        return list[index]
    }
    
    func myPrint(item:ItemType){
        
    }
    
    func test<T>(a: T) {
        
    }
}

通过上面的例子,看出只要实现类中指定ItemType的类型就好了。这个类型 还可以是个泛型,也可以是具体的数据类型。

上一篇下一篇

猜你喜欢

热点阅读