**### 为什么需要元组
为了回答这个问题,首先让我们脑补一个例子:\
假设有一个班级,数学科目经常小测((⊙o⊙)),数学老师非常用心的把每次成绩都记录下来了。如果我要拿到小明同学最近5次的数学成绩,应该怎么定义数据格式?
首先回顾一下,在c的时代,数据类型有这么几类:
基本类型 | 构造类型 | 指针类型 | 空类型 |
---|---|---|---|
整型 short int long | 数组 [] | 指针 * | void |
浮点型 float double | 结构体 struct | \ | |
\ | |||
字符类型 char | 共用体 union | \ | |
\ | |||
布尔类型 bool (C99增加) | 枚举类型 enum | \ | |
\ |
用c语言有限的数据类型,要怎么定义需要的数据呢?
char* name = "小明";
float scores[5] = {90,87,88.5,95,78};
看上去还不太复杂。\
再进一步想,如果实现一个c函数,由函数返回这些数据,怎么办?只能定义struct了。
//先声明一个struct
struct name_scores {
char *name;
float scores[5];
};
//给struct赋值
struct name_scores xiaoming = {"小明" , {90,87,88.5,95,78}};
//函数返回类型是结构体
return xiaoming;
这个解决方案,看上去真是just so so。
到了c++的时代,似乎可以试试类的概念,把char*也换成string。
//先声明一个类
class Student {
public:
string name;
float scores[5];
};
//实例化一个对象,赋值
Student xiaoming;
xiaoming.name = "小明";
xiaoming.scores = {90,87,88.5,95,78};
//函数中返回对象
return xiaoming;
然并卵,更麻烦了。
到了乔老爷子的时代,oc语言增加了NS开头的基本数据类,NSString NSArray NSDictionary都是非常常用的,我们可以试着组合一下数据。
//存储数据
NSString *name = @"小明";
NSArray *scores = @[@90,@87,@88.5,@95,@78];
NSDictionary *returnDic = @{@"name":name,@"scores":scores};
//返回字典
return returnDic;
这已经是最简单的写法,依然是比较复杂的形式。
所以,有没有一种简单的数据类型,可以轻松组合不同类型的数据?\
有!\
Swift的元组闪亮登场✨✨
//一行代码搞定
return ("小明",(90,87,88.5,95,78))
哇,只需一行代码,你买不了吃亏,买不了上当,元组就是这么霸气!\
有些人可能就不服气了,数组一样可以这么简洁,为什么不用数组?客官请继续看。
元组、数组、字典,合适才是最好
首先说说字典,字典是key:value键值对,它适合将不同种类、不同用途的数据组合在一起,通过key值进行索引。
优点:
- 通过key值进行索引,查找效率高
- 通过key值进行数据标注,可读性高,易于区分多种数据
- key值唯一,增删改可以保证数据唯一性
缺点:
- 一个value必须对应一个key,尽管有时不需要key
- key值顺序不定,字典对key值表进行了hash,所以不方便存储对顺序敏感的数据
具体到小明的例子,数据格式如下
var name_score : Dictionary = ["name":"小明","scores":[90,87,88.5,95,78]]
我们试着读取其中的数据
var name = name_score["name"] //打印值为Optional(小明)
var scores = name_score["scores"] //打印值为Optional((90,87,88.5,95,78))
而如果print(name_score)
,会发现输出的key值顺序发生了变化
字典输出,观察key值顺序
接下来,我们再看看数组。\
最早在c语言中,数组用来存储多个相同类型的数据,到了OC不再限定存储数据的类型,Swift也沿用了OC的传统。这也是小明的例子中争议的来源,用数组也可以解决问题呀。
那么我们说说数组的优缺点吧。
优点
- 数据存储顺序固定,增删改也通过index来进行
- 集成了遍历方法,适合对大量同类数据的处理
- 不需要定义key,写法相对简单
缺点
- 访问特定数据时,查找效率不高
- 处理特定数据时,需要牢记数据的index,可读性不好,容易产生错位处理
仍以小明为例
var name_score = ["小明",[90,87,88.5,95,78]]
访问数据的方式如下
var name = name_score[0] //打印值为小明
var score = name_score[1] //打印值为(90,87,88.5,95,78)
我们print(name_score)
,可以看一下结果
数组输出,顺序很重要
Swift已经对Array和Dictionary做了大量改良,非常方便使用。可是元组又可以为我们带来什么呢?
首先,当我们在Array中放置不同类型的数据时,我们无法再对每个数据的type做定义。\
["小明",[90,87,88.5,95,78]]可以被修改为[1,[90,87,88.5,95,78]],而1显然不是正确的名字格式
\
而元组可以定义元素的类型\
var tuple : (String, Array) = ("小明",[90,87,88.5,95,78])
\
更深一步,元组嵌套元组每一个元素的类型都可以定义\
var tuple : (String, (Float,Float,Float,Float,Float)) = ("小明",(90,87,88.5,95,78))
其次,数组的元素个数可能发生改变,我可以增加、删除元素\
name_score.append("添加一个字符串")
\
name_score.removeAtIndex(1)
\
而元组一旦定义,其元素个数确定,不能增加、删除字典必须定义key,而元组不需要。当然,如有必要,你还可以为每个元素命名
var tuple = (name:"小明",[90,87,88.5,95,78])
\
tuple.name 等同于 tuple.0
字典的存储顺序不确定,而元组是固定的
通过上面几个简单的对比分析,我们发现,元组综合了数组、字典、甚至struct的一些优点,是对数据类型的一个强力补充。
下面分析一下元组的优缺点。
优点
- 元组可以同时存储多种类型元素,且元素类型固定,以保证数据安全,除非你定义数据类型为Any。编译器会对赋值参数类型进行检查
- 元组的元素个数固定,不允许增加、删除,编译器会严格校验赋值参数个数
- 无需定义key,但是必要时可以为数据命名,方便数据访问
- 适合同时遍历多元数据,例如官方文档的例子\
for (index, value) in shoppingList.enumerate()
缺点
- 不适合存储大量数据,因为元组不支持append、remove等方法
- 考虑到工程实际情况,后端使用的语言可能不支持元组,需要转换为其他格式
所以说,元组适合应用于组合少量的多元的数据,与数组、字典结合使用可以产生强大威力。