轉載:多范式 程式設計語言-以 Swift 為例

原文來自infoq,作者 郭麟

本文以Swift語言為例,介紹了什麼是多范式程式設計語言;同時也介紹了當今比較流行的幾種程式設計范式,值得一讀。故收藏之,原文連結于此

Swift的程式設計范式

程式設計范式是程式語言背後的思想。代表了程式語言的設計者認為程式應該如何被構建和執行。常見的程式設計范式有:過程式、面向對象、函數式、泛型編程等。

一些編程語言是專門為某種特定範式設計的,例如,C語言過程式編程語言短暫聊天Java是較純粹的面向對象編程語言;哈斯克爾、方案、Clojure是函數式編程語言。

另外一些編程語言和編程範式的關係並不一一對應,如Python、斯卡拉、Groovy同時支持面向對象和一定程度上的函數式編程。Swift 也是支持多種編程範式的編程語言。

由於代表了語言背後的思想,編程範式很大程度上決定了語言會呈現為何種面貌。用不著深入學習,僅僅瀏覽代碼,就能發現Scala和Swift很類似,這是因為它們支持的編程範式是類似的;Scheme和Swift看起來就相差很遠,這是因為它們支持的編程範式很不一樣。對於理解一門編程語言而言,相對於語言的語法和編寫經驗,理解語言的編程範式更重要。因為,就像看一本書,琢磨作者如何用詞,如何構建章節是很重要,但更重要的是理解書所要表達的思想。

Swift即支持面向對象編程範式,也支持函數式編程範式,同時還支持泛型編程。Swift支持多種編程範式是由它的目標決定的。Swift創造的初衷就是提供一門實用的工業語言。不同於Haskell這類出自大學和研究機構的具有學術性質的編程語言。蘋果推出Swift時就帶著著明確的商業目的:Mac OS和iOS系統的主要編程語言 Objective-C已顯老態,Swift將使得蘋果系統的開發者擁有一門更現代的編程語言,從而促進蘋果整個生態圈的良性發展。

Swift的設計和開發無不體現著“實用的工業語言”這一目標。這決定了 Swift無法做極端的語言實驗,它需要在理智地面對現實的基礎上,謹慎地尋求突破。這就決定了Swift需要繼承歷史遺產,在照顧現在大多數程序員的現實需求基礎上,面向未來有所發展。

面向對象

面向對象編程的核心概念是繼承,多態,和封裝。以對象構建程序的基本單元的面向對象編程語言中,繼承提供了一種複用代碼的方法;多態提供了更高的抽象能力,使得我們可以設計出更通用的程序;封裝提供一種使用代碼更為便捷安全的機制。Swift擁有以上所有的面向對象特性。所以,Swift是一門完備的面向對象編程語言。

Swift繼承了Objective-C面向對象方面的主要特性,提供以類為主的封裝和繼承機制。但給予了結構體(結構)和枚舉(枚舉)更豐富的面向對象特徵,使它們可以用於封裝更為複雜的對象。另外,相對於 Objective-C,Swift是一門更為安全的語言。

單繼承,多協議

在繼承上,Swift不同於C++可以繼承一個或者若干個類,而類似於 Objective-C和Java,只能單繼承。但Swift可以實現多個協議(Java 中對應的是接口 Interface)。這在一定程度上彌補了沒有多繼承的局限,同時又避免了多繼承難以控制的缺陷。

除了實現協議,Swift還可以實現多個擴展(Extension)。擴展是一種向已有的類,枚舉或者結構體添加新功能的方法。擴展和Objective-C中的分類(Category)類似,但與Objective-C中的分類不同的是,Swift中的擴展沒有名字。

更強大的結構體,枚舉

C++和Java等大部分面向對象編程語言主要以類(Class)作為實現面向對象的基本結構。Swift則賦予了結構體(Struct)和枚舉(Enum)更多的面向對象特徵,使結構體和枚舉也能承擔部分數據封裝工作。在其他一些語言需要用類來解決的場景中,Swift可以使用結構體和枚舉類型,而且更為合適。例如,Swift的Array和Dictionary是用結構體實現,而不是用類實現的,這不同於大多數編程語言。

Swift的結構體和枚舉可以像類一樣,完成下列事情:

  • 定義屬性
  • 定義方法
  • 擁有構造器
  • 可以被擴展(Extension)
  • 可以遵守協議 (協議)

在封裝這一點上,結構體和枚舉幾乎和類完全一致。不同的地方是,結構體和枚舉是不能繼承或者被繼承的。所以,這兩種數據類型也就沒有多態性。

總結一下,Swift中的類和其他面向對象編程語言的類一樣是面向對象語言的核心概念,具有面向對象的基本特徵。Swift的結構體和枚舉擁有比其他面向對象編程語言更多的面向對象特性,可以封裝更複雜的對象。但不可繼承,也就沒有了多態性。

更多的值類型,而不是引用類型

結構體,枚舉與類的另外一個區別是:結構體和枚舉是值類型,而類是引用類型。

值類型在賦值和作為函數參數被傳遞時,實際上是在進行複制,操作的是對象的拷貝。Swift中有大量值類型,包括Number,String,排列,Dictionary,元組,Struct和Enum等。

引用類型在賦值和作為函數參數被傳遞時,傳遞的是對象的引用,而並不是對象的拷貝。這些引用都指向同一個實例。對這些引用的操作,都將影響同一個實例。

在Swift中區分值類型和引用類型是為了將可變的對象和不可變的數據區分開來。可變的對象,使用引用類型;不可變的數據,使用值類型。值類型的數據,可以保證不會被意外修改。值類型的數據傳遞給函數,函數內部可以自由拷貝,改變值,而不用擔心產生副作用。在多線程環境下,多個線程同時運行,可能會意外錯誤地修改數據,這常常會是一種難以調試的bug。而使用值類型,你可以安全地在線程間傳遞數據,因為值類型傳遞是拷貝,所以無需在線程間同步數據變化。這就可以保證代碼線程環境下的安全性。

結構體是值類型,暗示了結構體應該主要用於封裝數據。例如,三維坐標系中的點Point,代表幾何形狀的大小的Size等。而類是引用類型,意味著類應該用於封裝具有狀態的,可以繼承的對象。例如,人,動物等。

斯威夫特中,排列、Dictionary、String都是值類型,它們的行為就像C語言中的Int一樣。你可以像使用Int一樣簡單安全地使用Array,而不用考慮深度拷貝之類煩人問題。Swift增強了對值類型的支持,鼓勵我們使用值類型。因為值類型更安全。更多地使用值類型,將有助於我們寫出行為更可預測,更安全的代碼。

更安全的語言

類型安全語言

Swift 是強類型語言,這意味著Swift禁止錯誤類型的參數繼續運算。例如,你不能讓 String 和 Float 相加。這與 C# 和 Java 一致;而與C和Javascript這類弱類型語言不一樣。

Swift是靜態類型語言,這意味著Swift中變量是在編譯期進行類型檢查的。編譯時,編譯器會盡力找出包括類型錯誤在內的相關錯誤。例如,String和Int相加這種類型運算錯誤,編譯器在編譯時就能告訴你,而不會在運行時才報錯。這與C#和Java一致;而與Python和Ruby這類動態類型語言不一樣。

Swift 不允許不正確的類型運算或類型轉換發生,所以 Swift 是類型安全的。

Swift 支持類型推導,並且有一個相當不錯的類型推導器。大部分情況下,你都不用聲明類型,編譯器可以根據上下文為你推導出變量的類型。

安全的初始化過程

Swift中類(包括結構體和枚舉)的初始化過程類似於 Java 的設計。Swift 有一類特別的方法,被作為初始化方法,它們沒有func前綴,而是以init為方法名。這不同於 Objective-C 中的初始化方法只是一個普通的方法。對於初始化方法的特殊處理可以在語言機制上保證初始化方法只被調用一次。這種機制在 Objective-C 中是不存在的,在 Objective-C 中,初始化方法就像其它的普通方法一樣,可以被多次調用。

Swift中初始化方法必須保證所有實例變量都被初始化。Swift初始化方法要求特殊的初始化順序。先保證當前類的實例變量被初始化,再調用父類的初始化方法完成父類實例變量的初始化。

Swift保證了初始化方法只會被調用一次,同時所有的實例變量都會被初始化。這使得Swift初始化過程很安全。

安全的重寫

Swift提供了重寫(Overriding)保護機制。如果要重寫基類的方法,就必須在子類的重寫方法前加上overriding關鍵字。這麼做是向編譯器聲明你想提供一個重寫版本。編譯器會確認,基類裡是否存在具有相同方法定義的方法。如果,基類中沒有相同的方法定義,編譯器就會報錯。另一方面,如果沒有加上overriding關鍵字的方法和基類的某個方法的定義相同,編譯器也會報錯,以防止意外的重寫行為。這樣就能從兩方面保證重寫行為的正確性。

選配

Swift中的Optionals讓我們能夠更安全地應對有可能存在,也有可能不存在的值。在Objective-C裡我們主要依靠文檔來了解一個API是否會返回nil。Optionals則讓我們將這份責任交給了類型系統。如果API的返回值聲明為Optional,就表示它可以是nil。如果它不是Optional,就表示它不可能是nil。

在Swift中,類型後面加問號聲明Optional類型,以及感嘆號!對 Optional類型拆包都只是語法糖。Optionals其實是由枚舉實現的:

 

也就是說,可選的 其實是一種枚舉類型。我們通過語言的類型系統來明確可能為 nil 的情況。這比Objective-C中使用文檔來說明要安全得多。

面向對象編程總結

現在絕大部分程序員的工作語言仍然是面向對象編程語言。大部分流行的現代編程語言都會允許你創建對象。面向對象編程語言易於建模。因為,對象和類似乎很容易和現實世界中的事物和概念對應。但編程實踐表明,任何東西都成為對象並不是一件好事情。舉一個Java中的蹩腳例子:Java中只有對象才能作為參數傳入函數(當然還有原始類型Primitive Type),所以為了將函數作為參數傳遞給另一個函數,需要將函數包裹在一個對像中,通常會使用一個匿名類(這也是Java中,監聽器 Listener通常的實現方法),而這個類不會有其他作用,只是為了滿足 Java一切皆為對象的設計,從而通過編譯。

Java 擁有純粹的面向對象概念。它從設計之初,就希望以一切皆為對象的純對像模型來為世界建模。但發展到現在,Java 中加入了越來越多非對象的東西。引入了閉包,從而獲得了函數式編程中的一級函數;引入泛型,從而獲得了參數化的類型。這可能暗示了,這個世界是如此豐富多彩,使用單一模型為世界建模並不會成功。

Swift 在追求統一純粹的編程範式這一點上並不固執。Swift完整地支持面向對象編程,擁有完備的面向對象基礎概念。這使得熟悉面向對象編程的程序員學習和使用Swift的成本降低了。Java或者Objective-C 程序員對 Swift 的很多概念會覺得很熟悉。對他們而言,學習Swift並不困難,很快就能將Swift投入到實際生產之中。

同時,Swift 還一定程度上支持函數式編程風格。在適合函數式編程的場景下,同時程序員又擁有函數式編程的思維和能力時,可以使用 Swift 以函數式的編程方法改善生產力。這將在下一章詳細介紹。

函數式編程

函數式編程是一種以數學函數為程序語言建模的核心的編程範式。它將計算機運算視為數學函數計算,並且避免使用程序狀態以及可變對象。函數式編程思想主要有兩點:

  • 以函數為程序語言建模的核心
  • 避免狀態和可變性

函數是函數式編程的基石。函數式編程語言的代碼就是由一個個函數組合而成的。編寫函數式語言的過程就是設計函數的過程。大規模程序由成千上萬的函數組成,為了有效的組合這些函數。函數式編程語言,會盡量避免狀態,避免可變對象。沒有可變的狀態,就使得函數式語言中的函數變為了純函數。純函數更容易模塊化,更容易理解,對於復用是友好的。

函數

函數式編程的核心是函數,函數是“頭等公民”。這就像面向對象語言的主要抽象方法是類,函數式編程語言中的主要抽象方法是函數。Swift中的函數具有函數式語言中的函數的所有特點。你可以很容易地使用Swift 寫出函數式風格的代碼。

高階函數,一級函數

高階函數,指可以將其他函數作為參數或者返回結果的函數。

一級函數,進一步擴展了函數的使用範圍,使得函數成為語言中的“頭等公民”。這意味函數可在任何其他語言構件(比如變量)出現的地方出現。可以說,一級函數是更嚴格的高階函數。

Swift 中的函數都是一級函數,當然也都是高階函數。

前文中舉過Java中為了將函數作為參數傳遞給另外一個函數,需要將函數包裹在一個多餘的匿名類中的蹩腳例子。Swift函數都是一級函數,可以直接將函數作為參數傳遞給另外一個函數。這就避免了 Java 裡出現的這種多餘的匿名類。

閉包

閉包是一個會對它內部引用的所有變量進行隱式綁定的函數。也可以說,閉包是由函數和與其相關的引用環境組合而成的實體。函數實際上是一種特殊的閉包。

Objective-C在後期加入了對閉包支持。閉包是一種一級函數。通過支持閉包,Objective-C拓展其語言表達能力。但是如果與Swift的閉包語法相比,Objective-C的閉包會顯得有些繁重複雜。 以下示例顯示了Swift閉包語言的簡潔和優雅:

 

該例中,map 函數遍歷了數組,用作為函數參數被傳入的閉包處理了數組裡的所有元素,並返回了一個處理過的新數組。例子中可以看到,Swift 中使用 {}來創建一個匿名閉包。使用 來分割參數和返回類型。在很多情況下,由於存在類型推導,可以省略類型聲明。

不變性

在介紹 Swift 的不變性之前,先討論一下Haskell這門純函數式語言。這將有助於我們對於不變性有更深刻的理解。

簡單而言,Haskell 沒有變量。這是因為,Haskell追求更高級別的抽象,而變量其實是對一類低級計算機硬件:存儲器空間(寄存器,內存)的抽象。變量存在的原因,可以視為計算機語言進化的遺跡,比如在初期直接操作硬件的彙編語言中,需要變量來操作存儲過程。而在計算機出現之前,解決數學計算問題都是圍繞構建數學函數。數學中,不存在計算機語言中這種需要重複賦值的變量。

Haskell基於更抽象的數學模型。使用Haskell編程只需專注於設計數據之間的映射關係。而在數學上,表示兩個數據之間映射關係的實體就是函數。這使得編寫Haskell代碼和設計數學函數的過程是一致的,Haskell 程序員的思路也更接近數學的本質。Haskell摒棄了變量的同時,也拋棄了循環控制。這是因為沒有變量,也就沒有了控制循環位置的循環變量。這也很好理解。回憶一下我們在學習計算機之前的數學課程中,也無需使用到for這類概念。我們還是使用函數處理一個序列到另外一個序列的轉換。

不變性導致另外一個結果,就是純函數。沒有可變的狀態,沒有可變對象,就使得函數式語言中的函數變為了純函數。純函數即沒有副作用的函數,無論多少次執行,相同的輸入就意味著相同的輸出。一個純函數的行為並不取決於全局變量、數據庫的內容或者網絡連接狀態。純代碼天然就是模塊化的:每個函數都是自包容的,並且都帶有定義良好的接口。純函數具有非常好的特性。它意味著理解起來更簡單,更容易組合,測試起來更方便,線程安全性。

Swift提供了一定程度的不變性支持。在Swift中,可以使用 聲明普通的變量,也可以使用 快捷方便地聲明不變量。

 

斯威夫特區分 <強大></強大> <強大></強大> 是為了使用編譯器來強制這種區分。Swift 中聲明了不變量,就必須在聲明時同時初始化,或者在構造器中初始化。除這兩個地方之外,都無法再改變不變量。Swift 中鼓勵使用不變量。因為,使用不變量更容易寫出容易理解,容易測試,松耦合的代碼。

不變性有諸多好處:

  • 更高層次的抽象。程序員可以以更接近數學的方式思考問題。
  • 更容易理解的代碼。由於不存在副作用,無論多少次執行,相同的輸入就意味著相同的輸出。純函數比有可變狀態的函數和對象理解起來要容易簡單得多。你無需再擔心對象的某個狀態的改變,會對它的某個行為(函數)產生影響。
  • 線程安全的代碼。這意味著多線程環境下,運行代碼沒有同步問題。它們也不可能因為異常的發生而處於無法預測的狀態中。

不像 Haskell 這種純函數式編程語言只能申明不可變量,Swift提供變量和不可變量兩種申明方式。程序員可以自由選擇:在使用面向對象編程範式時,可以使用變量。在需要的情況下,Swift也提供不變性的支持。

惰性求值

惰性計算是函數式編程語言的一個特性。惰性計算的表達式不在它被綁定到變量之後就立即求值,而是在該值被取用的時候求值。

惰性計算有如下優點:

  • 首先,你可以用它們來創建無限序列這樣一種數據類型。因為直到需要時才會計算值,這樣就可以使用惰性集合模擬無限序列。
  • 第二,減少了存儲空間。因為在真正需要時才會發生計算。所以,節約了不必要的存儲空間。
  • 第三,減少計算量,產生更高效的代碼。因為在真正需要時才會發生計算。所以,節約那部分沒有使用到的值的計算時間。例如,尋找數組中第一個符合某個條件的值。找到了之後,數組裡該值之後的值都可以不必計算了。

純函數式編程語言,如 Haskell 中是默認進行惰性求值的。所以,Haskell 被稱為惰性語言。而大多數編程語言如Java、C++ 求值都是嚴格的,或者說是及早求值。Swift 默認是嚴格求值,也就是每一個表達式都需要求值,而不論這個表達式在實際中是否確實需要求值。但是,Swift 也提供了支持惰性求值的語法。在需要惰性時,需要顯式聲明。這為開發者在 Swift 中使用惰性提供了條件。

下面的例子展示了將默認是嚴格求值的數組變為惰性序列:

 

將獲得如下結果:

 

結果顯示 seq 是一個惰性序列。它的值只有在需要時才會真正發生計算。

函數式編程總結

函數式編程語言並不年輕,它的歷史和麵向對象編程一樣悠久。1958年被創造出來的Lisp是最古老的函數式編程語言。它比C語言年代更為久遠。但直到最近,函數式編程思想才逐漸被重視。幾乎所有新發明的編程語言都或多或少受到了函數式編程思想的影響。蟒蛇、斯卡拉、Groovy的、Swift都有一級函數,閉包。使得你可以將函數直接傳給另外一個函數,函數也能夠以返回值形式被另一個函數返回。消除狀態,提供不變性的好處越來越多被接受,斯卡拉、Groovy的、Swift都提供了聲明不可變對象的方法,以支持編寫更趨近於函數式風格的代碼。

函數編程語言有其優秀的地方,也許將來會成為一個重要的編程範式。但是,函數式編程的重要性可能更多會間接地體現在影響其他編程語言的發展上。未來,可能很難出現一門主要以函數式編程範式設計的主流編程語言。如同Java這樣的以單一編程範式(面向對象)構建,而成為主流的編程語言的機會應該不會太多了。如同Haskell這樣追求純粹的函數式編程語言,更多的可能只是一個偏學術的語言實驗。

容我再重複一次上一節提到的理由:這個世界是如此豐富多彩,使用單一模式為世界建模可能並不會成功。當然,這類預測常常會被打破。如果,將來計算機領域出現了能解決所有問題的統一範式,我將很樂意再次學習和討論它。但如果僅僅討論現狀的話,我們仍然不得不面對一個分裂和折衷的世界。

Swift並不是一門主要以函數式編程範式構建的語言,它更多的是藉鑑融合了函數式編程一些優秀思想(更靈活強大的函數,不變性的優點)。Swift在大多數的場景下,仍然主要會以面向對象編程語言的面目出現。因為,作為另一門面向對象編程語言Objective-C的繼任者,Swift 需要繼承Objective-C的遺產:可可。我們現在寫Swift代碼,大部分時候還是在Cocoa框架之上,可以說 Cocoa就是Swift的標準庫。在一個主要以面向對象語言編寫的框架中寫代碼,最合適的思維方式仍然會是面向對象的。Cocoa可以說是Swift得以在高起點出發的基礎,也可以說其發生胎換骨變化的阻礙。

Swift對函數式編程的支持,使得程序員多了一種選擇。Swift並不強迫程序員一定要以面向對象的方法思維。在場景合適的情況下,程序員可以選擇使用函數式風格編寫代碼。如果確實是合適的場景,就能夠改善生產力。

面向對象與函數式編程

如果,我們按語言範式給現在流行的語言分類,支持面向對象的編程語言應該會是最長的隊伍。現在大部分流行的現代編程語言都是面向對象的,它們都會允許你創建對象。但同時,你會發現比較流行的幾個編程語言,蟒蛇、Scala甚至Java都或多或少都受到了函數式編程語言的影響。它們都引入一些函數式編程的概念,可以在一定程度上編寫出具有函數式風格的代碼。

在熟悉了類面向對象編程語言之後,再接觸函數式編程語言,常常會覺得耳目一新,甚至隱約覺得函數式語言會是救世良方。那我們是否應該就此徹底轉向函數式編程語言呢?使用Haskell來拯救世界?

面向對象編程語言在大規模實踐之後,我們確實更深刻地了解了它們的缺點(例如,難以編寫多線程環境下的軟件應用;繼承並不是代碼復用的好方法)。函數式語言也確實有不少優點,有些優點恰恰就能解決面向對象語言的問題(純函數十分適應多線程環境,純函數天生就是模塊化的,對於代碼復用十分友好)。但是,函數式編程也許也存在某些問題。而這些問題,可能要在更大規模的業界實踐之後才會暴露出來。現在我們已經認識到,單純以對象為世界建模是有困難的。那麼以數學模型來為世界建模可能也並不會好到哪裡去。而可以確信的是,它們都有自己各自擅長的領域和環境。我們仍然還無法使用某種單一的編程範式來解決所有問題。

更大的現實是無數企業已經在面向對象編程語言上做了巨大的投資,即使現在面向對象編程已經暴露出一些問題,而函數式編程又呈現出不少能解決這些問題的優點,任何一個謹慎的人都不會,也不可能馬上拋棄面向對象編程,徹底全面地轉向函數式編程語言。

現實的選擇是支持面向對象編程的同時,提供函數式的支持。這樣,在大部分面向對象游刃有餘的地方,仍然可以使用面向對象的方法。而在適合函數式編程的地方,而你又擁有函數式編程的思維和能力時,還可以採用函數式的編程方法改善生產力。

Swift就是這樣一個現實的選擇。完善的面向對象支持,使Swift繼承了 Objective-C遺留下來的豐厚遺產。在Swift中使用Objective-C對象並不復雜。如果,你遇到一個對多線程安全性有要求的場景,需要使用函數式風格編寫這部分代碼,這在Swift中也是很輕鬆的。

泛型編程

泛型編程是另外一個有趣的話題。泛型為程語言提供了更高層級的抽象,即參數化類型。換句話說,就是把一個原本特定於某個類型的算法或類當中的類型信息抽像出來。這個抽像出來的概念在C++的 STL(Standard Template Library)中就是模版(Template)。STL 展示了泛型編程的強大之處,一出現就成為了C++的強大武器。除C++之外,C#、Java、Haskell等編程語言也都引入了泛型概念。

泛型編程是一個稍微局部一些的概念,它僅僅涉及如何更抽像地處理類型。這並不足以支撐起一門語言的核心概念。我們不會聽到一個編程語言是純泛型編程的,而沒有其他編程範式。但正因為泛型並不會改變程序語言的核心,所以在大多數時候,它可以很好地融入到其他編程範式中。C ++、斯卡拉、Haskell這些風格迥異的編程語言都支持泛型。泛型編程提供了更高的抽象層次,這意味著更強的表達能力。這對大部分編程語言來說都是一道美味佐餐美酒。

在Swift中,泛型得到廣泛使用,許多Swift標準庫是通過泛型代碼構建出來的。例如Swift的數組和字典類型都是泛型集合。這樣的例子在 Swift中隨處可見。

泛型函數

Swift函數支持泛型。泛型函數通過將函數參數和返回值定義為泛型類型,使得函數可以作用於任何適合的類型。下面展示了一個簡單的泛型函數:

 

泛型類型

除了泛型函數之外,Swift還可以自定義泛型類,泛型結構體和泛型枚舉。這樣的泛型類型可以作用於任何類型,其用法和Swift提供的 Array和Dictionary相同。

用一個棧(Stack)的例子展示泛型結構體的定義和使用。泛型枚舉和泛型類的定義和使用方法是相同的。

 

泛型類型參數T被用在了三個地方:

  • 創建數組items時,指定了items中可以存儲的數據類型;
  • 指定了函數push的參數類型;
  • 指定了函數pop的返回值類型。

泛型協議

而對於協議,Swift中沒有提供類似結構體或類那樣的方法來定義泛型協議。但我們可以使用typealias關鍵字定義該協議的關聯類型,這樣一定程度上可以模擬泛型協議的效果,例子如下:

 

實現該協議的類必須定義一個別名為 元件 的關聯類型。這和泛型的概念異曲同工,一定程度上實現了泛型協議。

泛型約束

在泛型的編程實踐中,我們會遇到一些需要對泛型類型做進一步約束的場景。類型約束為泛型參數指定了一個類型,或者要求其實現某個特定的協議。比如,`意味著泛型參數指代的對象需要遵守 Equatable 協議。

類型約束對泛型參數的類型做了一定約束,可以強制要求泛型參數代表的類型遵守某個協議。而where語句可以更進一步對類型約束中聲明的泛型參數所需要遵守的協議作出更詳細的要求。where語句也可以對協議的關聯類型作進一步約束。比如,你可以要求兩個泛型參數所遵守的協議的關聯類型是相同的。

泛型編程總結

總體而言,Swift提供了全面的泛型編程語法,讓程序員可以寫出抽象層次更高,更為靈活的代碼,在避免了重複代碼的同時,又能擁有良好的類型安全性。

總結

最後總結一下,Swift 是一門典型的多范式程式設計語言,支持面向對像是為了繼承面向對象編程豐厚的成果;支持函數式編程,是為了探索新的可能;支持泛型編程,則是一道美味的佐餐美酒。

Swift 允許程序員在大部分使用面向對象就游刃有餘的時候,輕鬆地繼續使用面向對象編程;而在適合函數式編程的場景下,同時程序員又擁有函數式編程的思維和能力時,還可以使用 Swift 以函數式的編程方法改善生產力;以及任何時候程序員都可以在 Swift 中使用泛型,提高抽象層次。

參考文檔


本文由 落格博客 原創撰寫:落格博客 » 轉載:多范式 程式設計語言-以 Swift 為例

轉載請保留出處和原文鏈接:https://www.logcg.com/archives/1045.html

關於作者

R0uter

如非聲明,本人所著文章均為原創手打,轉載請註明本頁面鏈接和我的名字。

註釋

發表評論

您的電子郵件地址不會被公開. 必填字段標 *