美文网首页
swift泛型

swift泛型

作者: BetterComingDay | 来源:发表于2017-07-04 10:54 被阅读14次

    泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,这种参数类型可以用在类型、函数和方法中。

    一、泛型函数

    下面就举个例子说明一下这个。其实好多文章都是举得这个例子,那我当然不能例外是不是,相同的例子奉上。
    定义两个普通的函数,分别实现Int类型,String类型两个参数值的交换。只要是想交换一种新的类型就需要写一个方法。

    func chageInt(a:inout Int, b:inout Int){
        let temp = a
        a = b
        b = temp
    }
    
    func changeString(a:inout String, b:inout String){
        let temp = a
        a = b
        b = temp
    }
    

    如果使用泛型,只需要一个方法就能搞定,

    func change<S>( a:inout S, b:inout S){
        let temp = a;
        a = b;
        b = temp;
    }
    
    var num1 = 1, num2=2
    print("交换前===",num1,num2)
    change(a: &num1, b: &num2)
    print("交换后===",num1,num2)
    

    控制台:

    交换前=== 1 2
    交换后=== 2 1
    

    这就是泛型函数的基本用法了,
    tips:
    1、inout 代表这个变量在参数内部是可以改变的。
    2、inout修饰的参数,在传值的时候需要穿参数的地址,用&修饰。

    二、泛型类型

    swift不但允许定义泛型函数,而且还允许定义泛型类型。这些自定义的泛型类型可以是类、结构体和枚举。
    接下来举例子时刻又到了,先上代码再说有何妙用,
    例子的功能是实现栈的操作,即后进先出。例子实现入栈、出斩操作。

    struct Stack<T>{
        //栈里边的元素
        var elements = [T]()
        //出栈
        mutating func pop(){
            elements.removeLast()
        }
        //入栈
        mutating func push(newValue:T){
            elements.append(newValue)
        }
    }
    
    var myStack = Stack<String>()
    myStack.push(newValue: "hello")
    print("栈里边的数据为",myStack.elements)
    myStack.push(newValue: "world")
    print("栈里边的数据为",myStack.elements)
    myStack.pop()
    print("栈里边的数据为",myStack.elements)
    

    控制台:

    栈里边的数据为 ["hello"]
    栈里边的数据为 ["hello", "world"]
    栈里边的数据为 ["hello"]
    

    这样无论你定义什么类型的栈,只要创建的时候把T替换为对应的类型就可以了。很方便。
    当然了,如果你想要为该结构体添加扩展,只需要直接把T当做数据类型来用就可以了。

    三、类型约束

    默认情况下,泛型函数和泛型类型可作用于任何类型,不过,有的时候需要对泛型函数和泛型类型中的类型做一些强制约束。可以指定一个类型参数必须继承自指定类,或者符合一个特定的协议或协议组合。语法如下:

    func 函数名<T:类名, U:协议名>(参数1:T, 参数2:U){}
    
    Snip20170704_12.png

    == 处程序报错是因为并不是所有的swift类型都可以用等式符(==)进行比较,例如,如果创建一个自定义的类或结构体,那么swift无法得知这个类或者结构体相等的标准是什么,所以此句代码报错,
    不过,swift标准库中定义了一个Equatable协议,该协议要求其遵守者必须实现等式符(==),从而能使用==对符合该协议的类型值进行比较。所有的swift标准类都自动支持Equatable协议。因此定义泛型时可以遵守该协议。如下所示:

    func findIndex<T:Equatable>(array:[T], index:T) -> Int?{
        for(i, item) in array.enumerated(){
            if item == index{
                return i
            }
        }
        return nil
    }
    
    print(findIndex(array: [1,2,3,4,5], index: 5) ?? "没有对应的元素")
    

    for循环详解

    四、关联类型

    在定义协议时,有时候会对协议遵守者的元素类型有要求,此时可以在协议内部声明一个或多个关联类型。通过associatedtype关键字来指定关联类型。
    为了更好的理解,接下来是例子时刻

    protocol Container{
        associatedtype ItemType
        mutating func append(item:ItemType)
    }
    

    Container协议定义以后,协议遵守者可以通过多种方式确定关联类型的实际类型,如下:

    1、普通类型定义
    struct Stack:Container{
        var items:[Int]
        
        //Container 协议实现部分
        typealias ItemType = String//因为下边的代码可以推断出是什么类型,所以这句话可写可不写。
        mutating func append(item:String){
            print(item)
        }
    }
    var s = Stack(items: [1,2,3])
    s.append(item: "1121212121212")
    
    2、泛型类型定义
    struct Stack<E>:Container{
        var items:[Int]
        
        //Container 协议实现部分
        mutating func append(item:E){
            print(item)
        }
    }
    var s = Stack<String>(items: [1,2,3])
    s.append(item: "1121212121212")
    
    五、where子句

    我的天我都不相信有人还会用这个东西,简直跟sql一样,好麻烦,具体用的时候再看吧。要疯了

    相关文章

      网友评论

          本文标题:swift泛型

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