Swift超基础语法(元组篇)

作者: S_Lyu | 来源:发表于2016-07-30 02:01 被阅读401次

    你对Swift中的元组了解多少呢?
    ...
    很有自信嘛
    ...
    看完这篇文章再说喽

    元组

    • 元组是Swift中特有的,OC中并没有相关数据类型
    • 元组是一种数据结构,它可以把多个值,组成一个复合值,元组内元素的类型无需相同

    元组的定义格式:

    let 元组名称 = (元素,元素...)
    

    数组?字典?元组!

    • 使用数组定义的数据
      缺点:在一个数组中,如果存在多种数据类型,所有的元素类型都将会一并变为NSObject
    例:
    let infoArray = ["lyu" , 18]
    let name = infoArray[0] //缺点:name的类型是NSObject,而不是String,也就是说我们是没有办法敲出name.characters这个方法的
    let length = name.characters.count  //编译报错
    
    • 使用字典定义的数据
      缺点:在一个字典中,如果其value值存在多种数据类型,所有的value类型都将会一并变为NSObject
    例:
    let infoDic = ["name" : "lyu" , "age" : 18]
    let name = infoDic["name"]  //缺点:name的类型是NSObject,而不是String,也就是说我们是没有办法敲出name.characters这个方法的
    let length = name.characters.count  //编译报错
    
    • 使用元组来定义数据:
      优点:元组中的数据是按照他们的真实类型来存储的
    例:
    let infoTuple = ("lyu" , 18)  //元组会为他的元素储存其真实类型
    let name = infoTuple.0  //name的类型为String
    let length = name.characters.count  //毫无压力的拿到字符串的长度
    

    元组的使用方法

    • 给元组中的元素起别名
    例:
    let errorTuple = (newName : "Not Found" , newCode : 404)
    let errorName = errorTuple.newName
    let errorCode = errorTuple.newCode
    //当然.0和.1仍然可以取值
    let errorName1 = errorTuple.0
    let errorCode1 = errorTuple.1
    
    • 给元组起别名的另一种方法:
      要注意的是,通过这种方法来创建元组是拿不到元组名字的
      缺点:拿不到元组的名字
      优点:快速解构
    例:
    let (newName , newCode) = ("Not Found" , 404)
    let errorName = newName
    let errorCode = newCode
    提示:这种方法来创建的元组相当于直接创建了两个常量
    

    元组的进阶使用方法

    • 与Switch搭配进行复杂条件的判断:
    例:招聘一个20岁以下的员工,并同时打印其个人信息
            let name = "lyu"  //姓名
            let age = 18  //年龄
            var personalInfo = [String : NSObject]()  //个人信息
            personalInfo["height"] = 1.80  //个人信息
            switch (age,name,personalInfo) {  //包装元组,元组中元素的命名要与姓名,年龄,个人信息完全一致
            case (let age , let name , let personalInfo) where age < 20:  //满足age<20则执行case
                print(age)
                print(name)
                print(personalInfo)
            default:
                print(age)
            }
    
    • 作为函数的返回值,来创建多个返回值的函数
    例:计算一个数组中奇数偶数的值,一并返回
            func getCount(nums : [Int]) -> (Int , Int) {  //将返回值构建为一个元组
                var oddCount = 0  //初始化偶数个数
                var evenCount = 0  //初始化奇数个数
                for num in nums {  //遍历数组
                    if num % 2 == 0 {  判断是否为偶数   
                        oddCount += 1
                    }
                    else  //反之为奇数
                    {
                        evenCount += 1
                    }
                }
                return (oddCount , evenCount) 返回元组:(偶数,奇数)
            }
            let nums = [12,14,15,2,77,13]
            let counts = getCount(nums)
            print(counts)
            print(counts.0)
            print(counts.1)
    
    • 函数作为元组的元素,进行多函数同时调用
    例:
            func test1() -> String{
                return "test1"
            }
            func test2() -> String{
                return "test2"
            }
            func test3() -> String{
                return "test3"
            }
            let funcTuple = (a : test1() , b : test2() , c : test3())
            print(funcTuple)
    
    • 交换值
      被交换的必须是变量,并且这两个变量类型必须相同
    例:
            var (x , y) = (11 , 22)
            (x , y) = (y , x)
            print(x , y)
    

    元组的超进阶使用方法

    • 以假乱真:使用元组代替结构体
    例:
            //定义结构体
            struct newS {
                var name : String
                var age : Int
            }
            let temp = newS(name : "lyu" , age :18)
            //定义元组
            let tuple = (name : "lyu" , age : 18)
            //使用元组和结构体
            print(tuple.name)
            print(temp.name)
    
    Tips:结构体?元组?
    我们发现这两个家伙还是有所不同的:元组并没有结构体的声明部分,所以如果只是临时使用,或临时拼凑一个结构体,那么建议使用元组
    如果你的需求超出了"临时"(根据你的代码自己判断喽~)的范围,那么还是建议将数据封装成结构体
    另外:也可以使用元组来代替"匿名结构体哦"
    
    • 处理数据的过程中,将某一个函数的返回值作为临数据传入另一方法中
      • 元组可以作为函数的参数
      • 元组也可以作为函数的返回值,既然如此,这种用法当然也可以成立了
    //元组作为函数返回值
    func getViewInfo() -> (r : Int , alpha : Double , location : (Double , Double)){
            return (255 , 0.5 , (100 , 100))
    }
    //元组作为函数参数
    func getAlpha(tuple : (r : Int , alpha : Double , location : (Double , Double))) -> Double{  
            return tuple.alpha
    }
    let alpha = getAlpha(getViewInfo())
    print(alpha)
    
    • 当然根据上一条使用方法,我们也可以想到本例也可以使用结构体来实现,如下:
            //声明结构体
            struct Location {
                var x : Double
                var y : Double
            }
            struct Info {
                var r : Int
                var alpha : Double
                var location : Location
            }
            //定义函数
            func getViewInfo() -> (Info){
                return Info(r: 255 , alpha: 0.5 , location: Location(x: 100 , y: 100))
            }
            func getAlpha(stc : Info) -> Double{
                return stc.alpha
            }
            //调用函数
            let alpha = getAlpha(getViewInfo())
            print(alpha)
    
    tips:
    为了两个函数而刻意定义两个结构体,这种做法显然太浪费了,所以这里才为大家介绍了上面元组代替结构体的方法
    
    • 具体定义元组类型
            //typealias相当于C/OC中的typedef,用于起别名
            typealias Tuple = (name : String , age : Int ,height : Double)  //这与结构体的声明及其相似
            func printTuple(tempTuple : Tuple){  //使用Tuple类型定义形参
                print(tempTuple)
            }
            //下面提供三种用法
            printTuple((name: "lyu" , age : 18 , height : 1.80))
            printTuple(Tuple("lyu" , 18 , 1.80))
            printTuple(("lyu" , 18 , 1.80))
    
    • 约束一个类型元素的个数
      当我们创建一个数组可变数组,并且希望这个数组未来存储7组数据,例如统计一周内的每日降雨量
    //做法1:我们首先想到使用一个数组来包装这7天的数据
            var info = [Int]()
            info.append(11)
    //缺点:这种做法没办法控制数组中元素的数量,如果外界添加元素的时候不小心添加了8个,就没办法按地球的逻辑解释了,难道真的有星期八~
    
    //做法2:使用元组包装数据
    var info : (Int,Int,Int,Int,Int,Int,Int,Int)  //什么?不是7个,一定是你撸多眼花了
    //优点:这样做可以把info中的元素个数约束为7个,多于少于7都会报错
    
    • 作为函数的可变参数
      当函数的参数数量不确定的时候
    例:
    func sum(numbers : Int...) -> Int{
                return numbers.reduce(0, combine: +)  //第一个参数为基值,代表在0的基础上累加
            }
            let result = sum(1,2,3)
    
    • 元组与泛型
      元组中元素的真实类型是根据元组中元素类型来确定的,所以与其让泛型来约束元组,还不如根据我们的需求来定义一个明确数据类型的元组,反过来控制泛型
      • 由元组的类型来指定函数的泛型
            //例:元组与泛型与函数
            func three<c1 , c2 , c3>(tuple : (c1 , c2 , c3)) -> c3{  //利用泛型来声明元组属性类型,此时元组的属性类型与泛型都还是不确定的
                return tuple.2
            }
            //随便传入一个元组,均可成功调用该函数
            let  height = three(("Lyu" , 18 , 1.88))  //调用three函数的那一时刻,Swift根据参数(元组)类型推导出three的泛型!此时拿到的height是明确的Double类型
    
    • 根据需求,由子类来指定父类泛型
            例:元组与泛型与类
            class superClass<c1 , c2 , c3>{  //定义父类,此时泛型不确定
                typealias numbers = (c1 , c2 , c3)  //利用此时不确定的泛型来声明一个元组
                func printNewNumbers(nums : numbers) -> Void {
                    print(nums)
                }
            }
            class childClass<c1 , c2 , c3> : superClass<c1 , c2 , c3> {  //定义子类,此时父类的泛型与子类相同,但子类的泛型不确定
            }
            let child = childClass<String , Int , Double>()  //实例化对象,我们可以在此处根据需求来确定泛型,此时父类与子类泛型均以确定,
            child.printNewNumbers(("lyu" , 18 , 1.80))  //创建元组作为参数
    
            //当然我们也可以这样写
            class superClass<c1 , c2 , c3>{
                typealias numbers = (c1 , c2 , c3)
                func printNewNumbers(nums : numbers) -> Void {
                    print(nums)
                }
            }
            class childClass<c1 , c2> : superClass<c1 , c2 , Double> {  //在此处确定元组中某一个元素的类型(当然,前提你真的确定这个元素的类型...)
            }
            let child = childClass<String , Int>()  //这时,我们只需要确定前两个元素的类型即可
            child.printNewNumbers(("lyu" , 18 , 1.80))
    
    tips:
    当我们需要封装一个函数,但却不明确要传入的参数(不只是元组),可以利用这种思想,举一个最简单的例子如下:
            func myNameOrAge<c1>(nameOrAge : c1) -> c1{
                return nameOrAge
            }
            let name = myNameOrAge("Lyu")  //这里name的类型是String而不是可选类型,也不是anyObject
            let age = myNameOrAge(18)  //这里age的类型是Int而不是可选类型,也不是anyObject
    也就是说:此时反过来看return nameOrAge这一句中已经拿到了nameOrAge的真是类型,假如我们在函数体内做一些复杂的运算,最终返回的值仍然是一个已知的类型,是不是比anyObject要好的多呢
    
    • 元组作为函数的参数
      • 利用有参元组,作为带外部参数函数的参数
            func sum(a a : Int , b : Int , hello : String) -> Int {
                return a + b
            }
            let tuple = (a : 1,b : 2, hello : "hello")  //利用有参元组作为带外部参数的函数的参数
            let result = sum(tuple)
    
    • 利用无参元组,作为不带外部参数函数的参数
            func sum(a : Int , _ b : Int , _ hello : String) -> Int {
                return a + b
            }
            let tuple = (1 , 2 , "hello")  //利用无参元组作为不带外部参数函数的参数
            let result = sum(tuple)
    
    • 一个函数返回的元组作为另一个函数的参数
            func getTuple() -> (Int , Int , String){
                return(1, 2, "hello")
            }
            func printTuple(tuple : (Int , Int , String)){
                print(tuple)
            }
            printTuple(getTuple())
            //这种传递方式可以让我们无需结构元组(返回值),即可完成多个数据的传递
    

    相关文章

      网友评论

        本文标题:Swift超基础语法(元组篇)

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