在Swift中使用泛型

作者: 忆辰念家 | 来源:发表于2019-10-25 17:40 被阅读0次

Swift 5.0 都发布这么久了,而泛型作为该语言的重要特性,还是非常有必要了解一下的。
在 Swift 泛型的运用几乎随处可见,在系统层面,Swift 标准库是通过泛型代码构建出来的,Swift 的数组和字典类型都是泛型集。在主流的轮子里,也是有大量的泛型使用。使用泛型可以提审代码的复用性。
下面就通过实例看看我们的代码怎么写:

1、函数中使用泛型

举个简单的例子哦,比如现在有个简单的需求,就是写一个方法,这个方法需要把传过来的整数参数打印出来。

简单需求卡卡的代码就出来啦:

 /// 打印一个整形数字
func myPrintInt(arg:Int){
     print(arg)
}

看着没啥毛病哦,产品姥爷又说我现在这个方法要支持字符串。

简单再给添加一个方法好啦:

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

产品:现在要支持Float、Array、Dictionary ......

这也好办啊:

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

很好,现在我要你传进去两个参数,而且参数类型要一致,你要怎么写。

下面的写法可以不?参数靠大家自觉。

    //参数类型千万要一样啊。。。。。
    func myPrintAny(any1:Any, any2:Any){
        print(any1)
        print(any2)
    }

写成这样的话就可以那赔偿走人啦。

这时候就应该使用泛型了。

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

方法的使用:

        myPrint(any1: 1, any2: 1)
        myPrint(any1: "1", any2: "1")
        myPrint(any1: ["1","2"], any2: ["3","4"])

这里就可以看出泛型的优势所在了,大大提升了代码的可复用性。而且同时也提升了代码的安全性。

泛型和Any的区别
从表面上看,这好像和泛型极其相似。Any 类型和泛型两者都能用于定义接受两个不同类型参数的函数。然而,理解两者之间的区别至关重要:泛型可以用于定义灵活的函数,类型检查仍然由编译器负责;而 Any 类型则可以避开 Swift 的类型系统 (所以应该尽可能避免使用)。

2、类中泛型

实现一个栈,栈里边的元素可以是任何类型,但是所有元素又必须是同一种类型,使用泛型实现的代码就是这样的。

//类作用域
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
    }
}

3、泛型类型约束

在实际运用中,我们的参数虽然可以不是特定的类,但是通常需要这个参数要实现某个协议或者是某个类的子类。这时候就要给泛型添加约束了,代码就是下面这一堆喽

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

protocol A {}

protocol B {}

看了上面的代码,可能有的小伙伴就迷茫啦,既然有YJKProtocolStack<T: A&B>, 为啥没有 YJKProtocolStack<T: A|B>呢,其实想想就可以明白,如果用 | 的话,T 表示的就不是一个指定的类型啦,这样和泛型的定义是不一致的。

4、关联类

在类及函数里都知道泛型怎么玩了,那么在协议里怎么用啦,是不是和类是一样的呢,写个代码看一下:

//Protocols do not allow generic parameters; use associated types instead
//一敲出来,编译器就提示你错误啦,并且告诉你怎么写了。
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 的类型就好啦。这个类型 还可以是个泛型,也可以是具体的数据类型。

还有一点要讲的就是结构体中使用泛型和类是完全一样的处理哦。

5、Where 语句

Where 其实也是做类型约束的,你可以写一个where语句,紧跟在在类型参数列表后面,where语句后跟一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型间的等价(equality)关系。

看看下面几个代码就行啦,不多说了

    func test4<T:A>(arg1:T){}
    func test5<T>(arg1:T) where T:A{}
    // 上面两个方法的作用是一模一样的

    //这个方法 arg1 和 arg2 只需是实现 C 协议的对象就好啦
    func test6<T1:C, T2:C>(arg1:T1, arg2:T2){}
   
    //这个方法 arg1 和 arg2 需要实现 C 协议, 并且 T1 与 T2 的泛型类型要一致
    func test7<T1:C, T2:C>(arg1:T1, arg2:T2) where T1.ItemType == T2.ItemType{}

    //这个方法 arg1 和 arg2 需要实现 C 协议, && T1 与 T2 的泛型类型要一致 && T1 的泛型 遵循A协议
    func test8<T1:C, T2:C>(arg1:T1, arg2:T2) where T1.ItemType == T2.ItemType, T1.ItemType:A{}

本文写到这里就没结束啦,简单介绍啦泛型在 Swift 中的使用,大家想要深入理解泛型,想要融会贯通、运用自如,还需要大家找时间多看看大神写的代码。

相关文章

  • 使用Web浏览器编译Swift代码,及Swift中的泛型

    使用Web浏览器编译Swift代码,及Swift中的泛型 使用Web浏览器编译Swift代码,及Swift中的泛型

  • Swift中泛型的使用

    在使用Swift开发的过程中,我们可能经常会碰到泛型。那么究竟什么是泛型?泛型作为Swift最为强大的特性之一,该...

  • 泛型

    泛型 1.为什么要有泛型?2.泛型有什么好处?3.Swift泛型语法4.泛型的使用 为什么要有泛型 在编程世界中,...

  • [ WWDC2018 ] - Swift 泛型 Swift Ge

    Swift 泛型历史 我们首先来回顾一下 Swift 中对于泛型支持的历史变更,看看现在在 Swift 中,泛型都...

  • 问题:泛型类,泛型结构体,泛型协议的功能特性都包含在Swift中

    Swift 包含泛型类,泛型结构体特性。泛型可以在类、结构体、枚举、全局函数或者方法中使用。 泛型协议是通过typ...

  • OneDayOneSwift[23] - Generics

    泛型是 Swift 的强大特性之一,许多 Swift 标准库是通过泛型代码构建的。事实上,泛型的使用贯穿了整本语言...

  • Java-API-集合框架(三)-泛型

    泛型的由来和基本使用 泛型的擦除 泛型类的使用 泛型方法的使用 泛型接口 泛型通配符(?) 通配符? 在api中的...

  • swift 泛型

    Swift-泛型学习和实例总结 - Mazy's Blog - CSDN博客 Swift中的泛型 - 简书

  • 2021-12-01

    swift5基本语法-泛型函数和泛型类型 Swift中泛型可以将类型参数化,提高代码复用率,减少代码量。 一、泛型...

  • Kotlin 泛型

    Kotlin 泛型 1. 泛型类 定义一个泛型类 使用 在继承中 使用 2. 泛型函数 使用 3. 泛型的擦除 无...

网友评论

    本文标题:在Swift中使用泛型

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