2015-06-23 103 views
9

我已經通過了Apple開發人員網站上的Swift教程,但我不理解泛型的概念。有人能夠用簡單的方式解釋它嗎?例如:Swift中的泛型2.0

func swapTwoValues<T>(inout a: T, inout b: T) { 
    let temporaryA = a 
    a = b 
    b = temporaryA 
} 
+0

偉大的問題,你應該考慮選擇一個這個問題的答案,如果一個滿足你的問題!這可以提高您的帖子的質量,從而使社區受益。 –

回答

11

如果沒有你給的例子使用泛型一個功能,你必須重載swapTwoValues你想每一個類型互換。例如:

func swapTwoValues(inout a: Int, inout b: Int) { 
    let temp = a 
    a = b 
    b = temp 
} 

func swapTwoValues(inout a: String, inout b: String) { 
    let temp = a 
    a = b 
    b = temp 
} 

// Many more swapTwoValues functions... 

上述函數之間唯一不同的是它們接受的類型;每個內部的代碼都完全相同。因此,最好寫一個可以採用任何類型的通用函數。

請務必注意,您不能用Any替代T。不能保證ab將是同一類型 - 例如,您不能交換IntString

1

本質上,它只是意味着它不是類型特定的。您可以使用T,只是寫的,而不是寫很多功能爲每種類型的IntDoubleFloatString

4

在你的例子中,T表示一個Type。並且一旦設置該類型對於整個功能是一致的。

func swapTwoValues<T>(inout a: T, inout b: T) { 
    let temporaryA = a 
    a = b 
    b = temporaryA 
} 

如果T是一個Int在一個參數的情況下,那麼它也必須是一個Int在參數b的情況下。作爲該功能的正常使用證明:

var valueA = 2 
var valueB = 4 
swapTwoValues(&valueA, b: &valueB) 

valueA // 4 
valueB // 2 

我們不能換一個String類型爲int的例如甚至是詮釋了雙,但只要類型相同,則該泛型方法將採取任何類型,因爲它在所有其他方面都沒有限制。

var valueA = "Hello" 
var valueB = "Swift" 
swapTwoValues(&valueA, b: &valueB) 

valueA // "Swift" 
valueB // "Hello" 

但這並不意味着多種類型被排除在泛型函數之外。您只需指定一個不同的字母來表示不同的類型(使用的字母無關緊要,因爲它是Type的第一個字母,所以簡單地使用T,但沒有理由不能用Q替換,或者任何其他盤符):

func swapTwoValues<T,S>(inout a: T, inout b: T, inout c: S, inout d: S) { 
    let temporaryA = a 
    a = b 
    b = temporaryA 

    let temporaryC = c 
    c = d 
    d = temporaryC 
} 

var valueA = 2 
var valueB = 4 

var valueC = "Hello" 
var valueD = "Swift" 
swapTwoValues(&valueA, b: &valueB, c:&valueC, d:&valueD) 

valueA // 4 
valueB // 2 

valueC // "Swift" 
valueD // "Hello" 

注:我們還不能換一件T爲S,因爲斯威夫特是一個強類型語言,我們也沒有安慰他們是相同的。

當涉及約束泛型類型的協議時,它變得更有趣。在這裏,我與UnsignedIntegerType這樣做:

func swapTwoValues<T: UnsignedIntegerType>(inout a: T, inout b: T) { 
    let temporaryA = a 
    a = b 
    b = temporaryA 
} 

var valueA:UInt = 10 
var valueB:UInt = 11 

swapTwoValues(&valueA, b: &valueB) 

現在只有類型如uint,UINT8,UInt32的,等是可以接受的,所有其他值都將被拒絕,並創建一個錯誤。

注意:使用協議約束類型的原因是爲了保證某些方法能夠正常工作。例如,如果需要通用函數來創建新的類型實例,那麼它必須採用init方法採用協議。 (您可以檢查Apple文檔中每種類型的協議採用情況。)

我們可以更進一步,使用where關鍵字來確定包含一個泛型集合中的類型:

func swapTwoValues<T: CollectionType where T.Generator.Element: UnsignedIntegerType>(inout a: T, inout b: T) { 
    let temporaryA = a 
    a = b 
    b = temporaryA 
} 

var valueA:[UInt] = [10,12,4] 
var valueB:[UInt] = [11,45,67] 

swapTwoValues(&valueA, b: &valueB) 

valueA // [11, 45, 67] 
valueB // [10, 12, 4] 

或者不喜歡的東西的支票,第二類是相當於元素的集合中的類型使用==

func swapTwoValues<T: CollectionType, S where S == T.Generator.Element>(inout a: T, inout b: T, inout c: S, inout d: S) { 
    let temporaryA = a 
    a = b 
    b = temporaryA 

    let temporaryC = c 
    c = d 
    d = temporaryC 
} 

延伸閱讀:事情變得更加有趣與protocol extensions in Swift 2因爲現在通用的功能,可以採取類型方法的特點,這使得它們遠M礦石可發現。