Swift超基础语法(元组篇)

你对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())
        //这种传递方式可以让我们无需结构元组(返回值),即可完成多个数据的传递
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容