Swift Type Casting

作者: Harder | 来源:发表于2015-06-15 15:09 被阅读192次

    在Swift中,有两种方式实现类型转换:is 和 as

    可以在类的层级中检查类实例的类型,或者在同一个类的层级中转换为其他类。

    例如,有如下类,及其子类:
    <pre><code>
    class MediaItem {
    var name: String
    init(name: String) {
    self.name = name
    }
    }

    class Movie: MediaItem {
    var director: String
    init(name: String, director: String) {
    self.director = director
    super.init(name: name)
    }
    }

    class Song: MediaItem {
    var artist: String
    init(name: String, artist: String) {
    self.artist = artist
    super.init(name: name)
    }
    }

    let library = [
    Movie(name: "Casablanca", director: "Michael Curtiz"),
    Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
    Movie(name: "Citizen Kane", director: "Orson Welles"),
    Song(name: "The One And Only", artist: "Chesney Hawkes"),
    Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
    ]
    </code></pre>

    数组library,swift推断出共有父类“MediaItem”,所以library是一个[MediaItem]数组。

    检查类型 is

    <pre><code>
    var movieCount = 0
    var songCount = 0

    for item in library {
    if item is Movie {
    ++movieCount
    } else if item is Song {
    ++songCount
    }
    }

    print("Media library contains (movieCount) movies and (songCount) songs")
    // prints "Media library contains 2 movies and 3 songs"
    </code></pre>

    类型转换(downcasting) as

    • as? 在不确定转换能否成功时使用。不能转换则返回nil
    • as! 在确定转换能成功时使用。如果类型错误,将会产生runtime error

    在下例中,无法确定item到底是Movie还是Song,所以适合使用as?
    <pre><code>
    for item in library {
    if let movie = item as? Movie {
    print("Movie: '(movie.name)', dir. (movie.director)")
    } else if let song = item as? Song {
    print("Song: '(song.name)', by (song.artist)")
    }
    }

    // Movie: 'Casablanca', dir. Michael Curtiz
    // Song: 'Blue Suede Shoes', by Elvis Presley
    // Movie: 'Citizen Kane', dir. Orson Welles
    // Song: 'The One And Only', by Chesney Hawkes
    // Song: 'Never Gonna Give You Up', by Rick Astley
    </code></pre>

    Any、AnyObject 类型的转换:

    • AnyObject,可以表示任意类的实例
    • Any,可以表示所有类型的实例,包括function type

    AnyObject

    使用Cocoa API时,通常返回[AnyObject]数组,这是因为Objective-C的数组没有描述内部对象类型。不过可以在调用的API的说明信息中得到数组内对象的类型。
    在这种情况下,就可以使用as!将AnyObject转换为更具体的类型,例如:
    <pre><code>
    let someObjects: [AnyObject] = [
    Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
    Movie(name: "Moon", director: "Duncan Jones"),
    Movie(name: "Alien", director: "Ridley Scott")
    ]
    </code></pre>

    因为知道数组中只有Movie类型的数据,所里可以使用as!直接将AnyObjiect转换为Movie类型
    <pre><code>
    for object in someObjects {
    let movie = object as! Movie
    print("Movie: '(movie.name)', dir. (movie.director)")
    }
    // Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
    // Movie: 'Moon', dir. Duncan Jones
    // Movie: 'Alien', dir. Ridley Scott
    </code></pre>

    更简洁的代码如下,直接将数组[AnyObject]转换为[Movie]数组
    <pre><code>
    for movie in someObjects as! [Movie] {
    print("Movie: '(movie.name)', dir. (movie.director)")
    }
    // Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
    // Movie: 'Moon', dir. Duncan Jones
    // Movie: 'Alien', dir. Ridley Scott
    </code></pre>

    Any

    下面是一个混合类型的数组,包含function类型,non-class类型
    <pre><code>
    var things = Any

    things.append(0)
    things.append(0.0)
    things.append(42)
    things.append(3.14159)
    things.append("hello")
    things.append((3.0, 5.0))
    things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
    things.append({ (name: String) -> String in "Hello, (name)" })
    数组内有两个Int,两个Double,一个String,一个(Double,Double)元组,一个Movie,一个闭包String -> String。

    通过在switch中使用 is 和 as,可以发现那些Any,AnyObject类型的常量、变量的具体类型。
    for thing in things {
    switch thing {
    case 0 as Int:
    print("zero as an Int")
    case 0 as Double:
    print("zero as a Double")
    case let someInt as Int:
    print("an integer value of (someInt)")
    case let someDouble as Double where someDouble > 0:
    print("a positive double value of (someDouble)")
    case is Double:
    print("some other double value that I don't want to print")
    case let someString as String:
    print("a string value of "(someString)"")
    case let (x, y) as (Double, Double):
    print("an (x, y) point at (x), (y)")
    case let movie as Movie:
    print("a movie called '(movie.name)', dir. (movie.director)")
    case let stringConverter as String -> String:
    print(stringConverter("Michael"))
    default:
    print("something else")
    }
    }

    // zero as an Int
    // zero as a Double
    // an integer value of 42
    // a positive double value of 3.14159
    // a string value of "hello"
    // an (x, y) point at 3.0, 5.0
    // a movie called 'Ghostbusters', dir. Ivan Reitman
    // Hello, Michael
    </code></pre>

    参考:The Swift Programming Language

    相关文章

      网友评论

        本文标题:Swift Type Casting

        本文链接:https://www.haomeiwen.com/subject/mmurqttx.html