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.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 13,491评论 0 23
  • 我和同学们去采茶的路上,经过一间孤零零的土房,大门紧闭着,窗户已经不见了,只留下一个黑漆漆看不到屋里情况的窗口。 ...
    藤木同学阅读 1,589评论 0 0
  • 你要记得那些大雨中为你撑伞的人, 帮你挡住外来之物的人, 黑暗中默默抱紧你的人, 逗你笑的人 陪你彻夜聊天的人, ...
    夏某某的善良笑容阅读 1,886评论 0 1
  • 记得有歌词我印象很深刻,“你赤手空拳来到这个人世间,为找那片海不止一切”,这其实就是一段经历,生活中的我们也曾像天...
    冰凉诗雨阅读 1,301评论 0 0
  • 好段: 我喜欢冬天的峨眉山,厚厚的积雪没过了小草和山径,形成了一个白花花的世界。 我不仅喜欢大自然的无限...
    淘越阅读 3,767评论 0 1

友情链接更多精彩内容