Swift

类型转换

本文详细介绍了 Swift 中的类型转换,包括使用 is 检查类型、使用 as? 和 as! 进行向下转型,以及 Any 和 AnyObject 的使用。

类型转换(Type Casting)用于检查实例的类型,或者将实例作为其类层次结构中的不同超类或子类来处理。在 Swift 中,类型转换使用 isas 操作符实现。

定义类层次结构

为了演示类型转换,我们定义一个基类 MediaItem 和两个子类 MovieSong

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")
]
// library 的类型被推断为 [MediaItem]

检查类型 (Checking Type)

使用类型检查操作符 is 来检查一个实例是否属于特定子类。

var movieCount = 0
var songCount = 0

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

print("Media library contains \(movieCount) movies and \(songCount) songs")
// 打印 "Media library contains 2 movies and 3 songs"

向下转型 (Downcasting)

某类型的常量或变量可能实际上属于一个子类。你可以尝试使用类型转换操作符 as?as! 将其向下转型为子类类型。

  • as?:返回一个可选值,当转型失败时返回 nil
  • as!:强制转型,当转型失败时会触发运行时错误。
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)")
    }
}

Any 和 AnyObject 的类型转换

Swift 提供了两种特殊的类型别名来处理非特定类型:

  • Any:可以表示任何类型,包括函数类型。
  • AnyObject:可以表示任何类类型的实例。
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)" })

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")
    }
}
在 GitHub 上编辑

上次更新于