2014-12-19 48 views
2

這裏是我的代碼:Swift通用函數錯誤?

func swapTwoValues<T>(inout a: T, inout b: T){ 
    let temp = a 
    a = b 
    b = temp 
} 
var aInt = 5 
var bInt = 98 
swapTwoValues(&aInt, &bInt) 

當通話功能swapTwoValues(), 「T」 是整型

但當我這個代碼更改

func swapTwoValues<T,S:String>(inout a: T, inout b: T , inout c: S){ 
    let temp = a 
    a = b 
    b = temp 
    c = "Hi" 
} 
var aInt = 5 
var bInt = 98 
var cStr = "Hello" 
swapTwoValues(&aInt, &bInt,&cStr) 

這會顯示錯誤,但爲什麼?

我設置爲「S」爲String類型,它似乎正確

回答

0

代碼<S: String>不應原因很簡單,這個字符串是一個結構和結構不能擴展工作。所以S實際上是一個無效的類型。

如果您想讓c成爲枚舉,您應該使用<S: RawRepresentable where S.RawType == String>

如果您正在考慮爲字符串類型添加功能,您應該有c爲普通字符串,然後在字符串上使用擴展來實現該功能。

如果你實際上想要擴展一個字符串作爲對象,你應該擴展NSString。

例如:

class MyString: NSString { 
    // My code 
} 

,然後你的通用變成了:<S: NSString>,這是完全有效的。

擴展NSString的缺點是類型現在是一個引用類型,但是這只是Swift的一部分,不能擴展(就繼承而言)結構。

+0

爲什麼struct不能被擴展?教程說「擴展爲現有類,結構或枚舉類型添加新功能」。 – 2014-12-19 07:03:26

+0

對不起,這是一個不好用的單詞。可以使用「擴展」來擴展結構。但是他們不能通過繼承來「擴展」。 不同之處在於對「擴展」有特殊限制(例如,它們不能存儲新的成員變量,這會增加類型的大小) – Zenton 2014-12-19 07:05:41

1

這不起作用的原因是因爲A: B語法需要一個通用的佔位符表示任何符合協議或從基類繼承的類型。由於String是一個結構,而不是一個協議或類,所以會出現一個錯誤(「從非協議類繼承,非類類型'String'」)。如果您嘗試枚舉類似Optional的枚舉,則會得到相同的結果

這是爲什麼呢?泛型的目的是讓你編寫多於一種可能類型的代碼,然後在編譯時讓Swift允許將這個函數應用於多種不同的類型以滿足這個要求。因此,當你說func f<S: String>(c: S)時,你會定義一個通用佔位符S,它只能代表一種String而沒有其他類型,這是毫無意義的 - 你可以l指定String作爲非泛型參數,即func f(s: String),因爲它沒有可能的其他類型。在另一方面

類確實允許繼承,所以如果你有一個類MyClass,你可以因爲在編譯時寫func f:<S: MyClass>(c: S),也許你可以通過在MyInheritedClass,從MyClass繼承的類。

雖然結構可以符合協議。因此,例如,假設你想寫的東西,交換隻有一個人比另一個更大的值:

func swapIfGreater<T: Comparable>(inout a: T, inout b: T) { 
    // this is allowed because conformance to the the 
    // Comparable protocol guarantees > is available 
    if a > b { 
     // avoid temporaries with this one weird trick :) 
     (a, b) = (b, a) 
    } 
} 

// i and j are Ints (a kind of struct) 
var i = 40, j = 30 
swapIfGreater(&i, &j) 

// s1 and s2 are Strings 
var s1 = "zebra", s2 = "aardvark" 
swapIfGreater(&s1, &s2) 

// Bool doesn’t support the Comparable protocol 
// (false is not 「less than」 or 「greater than」 true) 
// so this won’t compile: 
var b1 = true, b2 = false 
swapIfGreater(&b1, &b2) 

在編譯時,當swapIfGreater被調用時,斯威夫特看上去在插槽中使用的類型通用佔位符T(這裏是IntString),並檢查它們是否符合要求(它們需要符合協議Comparable)。如果是這樣,你可以認爲它是專門爲你傳入的每種有效類型寫入一個函數版本:

// It’s as if Swift writes two versions of swapIfGreater for you automatically: 
func swapIfGreater(inout a: Int, inout b: Int) { 
    if a > b { 
     (a, b) = (b, a) 
    } 
} 

func swapIfGreater(inout a: String, inout b: String) { 
    if a > b { 
     (a, b) = (b, a) 
    } 
} 
+0

如果您導入Foundation,則字符串將被隱式轉換爲NSString。由於NSString是一個類,我不知道S:String在這種情況下拋出錯誤。 – mustafa 2014-12-19 13:54:36