Type Constraints

The swapTwoValues function and the Stack type can work with any type. However, it is sometimes useful to enforce certain type constraints on the types that can be used with generic functions and generic types. Type constraints specify that a type parameter must inherit from a specific class, or conform to a particular protocol or protocol composition.

For example, Swift's Dictionary type places a limitation on the types that can be used as keys for a dictionary. As described in Dictionaries, the type of a dictionary's keys must be hashable. That is, it must provide a way to make itself uniquely representable. Dictionary needs its keys to be hashable so that it can check whether it already contains a value for a particular key. Without this requirement, Dictionary could not tell whether it should insert or replace a value for a particular key, nor would it be able to find a value for a given key that is already in the dictionary.

This requirement is enforced by a type constraint on the key type for Dictionary, which specifies that the key type must conform to the Hashable protocol, a special protocol defined in the Swift standard library. All of Swift's basic types (such as String, Int, Double, and Bool) are hashable by default.

You can define your own type constraints when creating custom generic types, and these constraints provide much of the power of generic programming. Abstract concepts like Hashable characterize types in terms of their conceptual characteristics, rather than their explicit type.

Type Constraint Syntax:

You write type constraints by placing a single class or protocol constraint after a type parameter's name, separated by a colon, as part of the type parameter list. The basic syntax for type constraints on a generic function is shown below (although the syntax is the same for generic types):

func someFunction<T: SomeClass, U: SomeProtocol>(some: T, someU: U) {
    // function body goes here
}

The hypothetical function above has two type parameters. The first type parameter, T, has a type constraint that requires T to be a subclass of SomeClass. The second type parameter, U, has a type constraint that requires U to conform to the protocol SomeProtocol.

Type Constraints in Action

Here's a non-generic function called findStringIndex, which is given a String value to find an array of String values within which to find it. The findStringIndex function returns an optional Int value, which will be the index of the first matching string in the array if it is found, or nil if the string cannot be found.

func findStringIndex(array: [String], valueToFind: String) -> Int? {
    for (index, value) in enumerate(array)
        if value == valueToFind {
            return index
        }
    }
    return nil
}

The findStringIndex function can be used to find a string value in an array of strings:
let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
if let foundIndex = findStringIndex(strings, "llama") {
println("The index of llama is (foundIndex)")
}
// prints "The index of llama is 2"

The principle of finding the index of a value in an array isn't useful only for strings, however. You can write the same functionality as a generic function called findIndex, by replacing any mention of strings with values of some type T instead.

Here's how you might expect a generic version of findStringIndex, called findIndex, to be written. Note that the return type of this function is still Int?, because the function returns an optional index number, not an optional value from the array. Be warned, though - this function does not compile, for reasons explained after the example:

func findIndex<T>(array: [T], _ valueToFind: T)->Int? {
    for (index, value) in array.enumerate() {
        if value == valueToFind {
            return index
        }
    }

    return nil
}

This function does not compile as written above. The problem lies with the equality check, "if value == valueToFind". Not every type in Swift can be compared with the equal to operator (==). If you create your own class or structure to represent a complex data model, for example, then the meaning of "equal to" for that class or structure is not something that Swift can guess for you. Because of this, it is not possible to guarantee that this code will work for every possible type T, and an appropriate error is reported when you try to compile the code.

All is not lost, however. The Swift standard library defines a protocol called Equatable, which requires any conforming type to implement the equal to operator (==) and the not equal to operator (!=) to compare any two values of that type. All of Swift's standard types automatically support the Equatable protocol.

Any type that is Equatable can be used safely with the findIndex(_:_:) function, because it is guaranteed to support the equal to operator. To express this fact, you write a type constraint of Equatable as part of the type parameter's definition when you define the function:

func findIndex<T: Equatable>(array: [T], _valueToFind: T)->Int? {
    for(index, value) in array.enumerate() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}

The single type parameter for findIndex is written as T: Equatable, which means "any type T that conforms to the Equatable protocol."

The findIndex(_:_:) function now compilles successfully and can be used with any type that is Equatable, such as Double or String:

let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
// doubleIndex is an optional Int with no value, because 9.3 is not in the array
let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
// stringIndex is an optional Int containing a value of 2.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市夕晓,隨后出現(xiàn)的幾起案子算利,更是在濱河造成了極大的恐慌悲没,老刑警劉巖暖庄,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剥悟,死亡現(xiàn)場離奇詭異钦铺,居然都是意外死亡张漂,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門读存,熙熙樓的掌柜王于貴愁眉苦臉地迎上來为流,“玉大人,你說我怎么就攤上這事让簿【床欤” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵尔当,是天一觀的道長莲祸。 經(jīng)常有香客問我,道長椭迎,這世上最難降的妖魔是什么锐帜? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮畜号,結(jié)果婚禮上缴阎,老公的妹妹穿的比我還像新娘。我一直安慰自己简软,他們只是感情好蛮拔,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布述暂。 她就那樣靜靜地躺著,像睡著了一般建炫。 火紅的嫁衣襯著肌膚如雪畦韭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天肛跌,我揣著相機與錄音艺配,去河邊找鬼。 笑死惋砂,一個胖子當著我的面吹牛妒挎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播西饵,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼酝掩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了眷柔?” 一聲冷哼從身側(cè)響起期虾,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎驯嘱,沒想到半個月后镶苞,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡鞠评,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年茂蚓,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剃幌。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡聋涨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出负乡,到底是詐尸還是另有隱情牍白,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布抖棘,位于F島的核電站茂腥,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏切省。R本人自食惡果不足惜最岗,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望朝捆。 院中可真熱鬧仑性,春花似錦、人聲如沸右蹦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽何陆。三九已至晨汹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贷盲,已是汗流浹背淘这。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留巩剖,地道東北人铝穷。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像佳魔,于是被迫代替她去往敵國和親曙聂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容

  • **2014真題Directions:Read the following text. Choose the be...
    又是夜半驚坐起閱讀 9,509評論 0 23
  • 我和同學們?nèi)ゲ刹璧穆飞暇舷剩?jīng)過一間孤零零的土房宁脊,大門緊閉著,窗戶已經(jīng)不見了贤姆,只留下一個黑漆漆看不到屋里情況的窗口榆苞。 ...
    藤木同學閱讀 210評論 0 0
  • 你要記得那些大雨中為你撐傘的人, 幫你擋住外來之物的人霞捡, 黑暗中默默抱緊你的人坐漏, 逗你笑的人 陪你徹夜聊天的人, ...
    夏某某的善良笑容閱讀 270評論 0 1
  • 記得有歌詞我印象很深刻碧信,“你赤手空拳來到這個人世間赊琳,為找那片海不止一切”,這其實就是一段經(jīng)歷音婶,生活中的我們也曾像天...
    冰涼詩雨閱讀 137評論 0 0
  • 好段: 我喜歡冬天的峨眉山衣式,厚厚的積雪沒過了小草和山徑寸士,形成了一個白花花的世界。 我不僅喜歡大自然的無限...
    淘越閱讀 589評論 0 1