1. 程式人生 > >有了陣列和字典,為何Swift還需要元組(tuples)?

有了陣列和字典,為何Swift還需要元組(tuples)?

**### 為什麼需要元組

為了回答這個問題,首先讓我們腦補一個例子:\
假設有一個班級,數學科目經常小測((⊙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值進行索引。

優點:

  1. 通過key值進行索引,查詢效率高
  2. 通過key值進行資料標註,可讀性高,易於區分多種資料
  3. key值唯一,增刪改可以保證資料唯一性

缺點:

  1. 一個value必須對應一個key,儘管有時不需要key
  2. 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的傳統。這也是小明的例子中爭議的來源,用陣列也可以解決問題呀。

那麼我們說說陣列的優缺點吧。

優點

  1. 資料儲存順序固定,增刪改也通過index來進行
  2. 集成了遍歷方法,適合對大量同類資料的處理
  3. 不需要定義key,寫法相對簡單

缺點

  1. 訪問特定資料時,查詢效率不高
  2. 處理特定資料時,需要牢記資料的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的一些優點,是對資料型別的一個強力補充。

下面分析一下元組的優缺點。

優點

  1. 元組可以同時儲存多種型別元素,且元素型別固定,以保證資料安全,除非你定義資料型別為Any。編譯器會對賦值引數型別進行檢查
  2. 元組的元素個數固定,不允許增加、刪除,編譯器會嚴格校驗賦值引數個數
  3. 無需定義key,但是必要時可以為資料命名,方便資料訪問
  4. 適合同時遍歷多元資料,例如官方文件的例子\
    for (index, value) in shoppingList.enumerate()

缺點

  1. 不適合儲存大量資料,因為元組不支援append、remove等方法
  2. 考慮到工程實際情況,後端使用的語言可能不支援元組,需要轉換為其他格式

所以說,元組適合應用於組合少量的多元的資料,與陣列、字典結合使用可以產生強大威力。