Type casting in Swift is implemented with the is and as operators. These two operators provide a simple and expressive way to check the type of a value or cast a value to a different type.
swift的类型转换是用is和as操作符实现。这两个操作符用简单和昂贵的方式来检查一个值的类型,或把一个值转换为另一个类型。
为类型转换定义类层次体系
You can use type casting with a hierarchy of classes and subclasses to check the type of a particular class instance and to cast that instance to another class within the same hierarchy. The three code snippets below define a hierarchy of classes and an array containing instances of those classes, for use in an example of type casting.
你可以在类和子类的层次体系上使用类型转换类检查一个特定类实例的类型或把此实例转换为另一个此层次体系上的类。下面的三段代码定义了一个类的层次体系和一个包含了这些类实例等数组。
The first snippet defines a new base class called MediaItem. This class provides basic functionality for any kind of item that appears in a digital media library. Specifically, it declares a name property of type String, and an init name initializer. (It is assumed that all media items, including all movies and songs, will have a name.)
第一段代码定义了一个新的基础类MediaItem。这个类为数字媒体的任何项目提供了基础的功能。他定义了一个string类型的属性name,一个初始化name的初始化方法(假设所有的媒体项目,包括电影音乐都有一个名字):
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
The next snippet defines two subclasses of MediaItem. The first subclass, Movie, encapsulates additional information about a movie or film. It adds a director property on top of the base MediaItem class, with a corresponding initializer. The second subclass, Song, adds an artist property and initializer on top of the base class:
下一段代码定义了MediaItem的两个子类。第一个子类,Movie,封装了电影的信息。在MediaItem类的基础上添加了director属性,还有一个相应的初始化方法。第二个子类,Song,在父类基础上增加了artist属性和初始化方法:
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)
}
}
The final snippet creates a constant array called library, which contains two Movie instances and three Song instances. The type of the library array is inferred by initializing it with the contents of an array literal. Swift’s type checker is able to deduce that Movie and Song have a common superclass of MediaItem, and so it infers a type of [MediaItem] for the library array:
最后一段代码创建一个常量数组library,library包含两个Movie实例和三个Song实例。library数组的类型是根据初始化时它的内容推断的。swift的类型检查器可以推导出Movie和Song都有一个共同的父类MediaItem,因此它推断library数组的类型是[MediaItem]:
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")
]
// the type of "library" is inferred to be [MediaItem]
The items stored in library are still Movie and Song instances behind the scenes. However, if you iterate over the contents of this array, the items you receive back are typed as MediaItem, and not as Movie or Song. In order to work with them as their native type, you need to check their type, or downcast them to a different type, as described below.
library存储的item依然是Movie和Song实例。虽然,如果你遍历此数组的内容,你获取到的item表示为MediaItem类型,而不是Movie和Song。要想获取它们原本的类型,你需要检查它们的类型或把它们向下转换为另一个类型。
类型检查
Use the type check operator (is) to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it is not.
使用类型检查操作符(is)来检查一个实例是不是一个子类的类型。如果此实例是该子类类型, 类型检查操作符返回true,否则返回false。
The example below defines two variables, movieCount and songCount, which count the number of Movie and Song instances in the library array:
下面的例子定义了两个变量,movieCount 和 songCount, 这两个变量用来计算library数组中Movie 和 Song实例等数量:
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")
// Prints "Media library contains 2 movies and 3 songs"
item is Movie returns true if the current MediaItem is a Movie instance and false if it is not. Similarly, item is Song checks whether the item is a Song instance. At the end of the for-in loop, the values of movieCount and songCount contain a count of how many MediaItem instances were found of each type.
如果当前MediaItem是一个Movie实例的话, item is Movie就返回true,否则返回false。相似的,item is Song检查一个item是不是一个Song实例。在for-in循环的最后,movieCount和songCount 包含了一共找到多少个两种类型的 MediaItem实例。
类型向下转换(Downcasting)
A constant or variable of a certain class type may actually refer to an instance of a subclass behind the scenes. Where you believe this is the case, you can try to downcast to the subclass type with a type cast operator (as? or as!).
一个确定类类型的常量或变量实际上或许指向一个子类的实例。遇到这种情况时,你可以使用类型转换操作符(as? 或 as!)来把类型向下转换为其子类类型。
Because downcasting can fail, the type cast operator comes in two different forms. The conditional form, as?, returns an optional value of the type you are trying to downcast to. The forced form, as!, attempts the downcast and force-unwraps the result as a single compound action.
由于类型向下转换可能会失败,所以类型转换操作符有两种不同的形式。条件形式:as?,返回一个你想向下转换的类型的可选类型。强制形式:as!,一个动作完成类型向下转换和类型拆包两个功能。
Use the conditional form of the type cast operator (as?) when you are not sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible.
如果你不确定类型向下转换是否会成功,则使用条件形式的类型转换操作符(as?).这个形式的操作符永远返回一个可选类型,如果无法向下转换,其值为nil。
Use the forced form of the type cast operator (as!) only when you are sure that the downcast will always succeed. This form of the operator will trigger a runtime error if you try to downcast to an incorrect class type.
如果你确定向下转换一定成功,则使用强制形式的类型转换操作符(as!). 如果你对一个错误的类型进行向下转换,这个形式的操作符将会触发一个运行时错误。
The example below iterates over each MediaItem in library, and prints an appropriate description for each item. To do this, it needs to access each item as a true Movie or Song, and not just as a MediaItem.
下面的例子将遍历library数组中的每个MediaItem,并打印相应的描述。为了完成这个功能,就需要把每个item作为真正的 Movie 或 Song来处理,而不是MediaItem。
In this example, each item in the array might be a Movie, or it might be a Song. You don’t know in advance which actual class to use for each item, and so it is appropriate to use the conditional form of the type cast operator (as?) to check the downcast each time through the loop:
在此例子中,数组中的每个item有可能是Movie,也可能是Song。你不可能事先知道类怎么使用每个item,因此就应该使用条件形式的类型转换操作符(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)")
}
}
// 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
Any 和 AnyObject的类型转换
Swift provides two special types for working with nonspecific types:
Any can represent an instance of any type at all, including function types.
AnyObject can represent an instance of any class type.
swift提供了两种特殊的类型,它们没有指定的类型:
Any,可以表示任意类型的实例,包括函数类型。
AnyObject,可以表示任意类类型的实例。
Use Any and AnyObject only when you explicitly need the behavior and capabilities they provide. It is always better to be specific about the types you expect to work with in your code.
当你明确需要它们的功能时,就可以使用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)" })
The things array contains two Int values, two Double values, a String value, a tuple of type (Double, Double), the movie “Ghostbusters”, and a closure expression that takes a String value and returns another String value.
things数组包括两个int值,两个double值,一个string值,一个元组类型 (Double, Double),,movie “Ghostbusters”,一个闭包表达式---接收一个string值,返回另一个string值。
To discover the specific type of a constant or variable that is known only to be of type Any or AnyObject, you can use an is or as pattern in a switch statement’s cases. The example below iterates over the items in the things array and queries the type of each item with a switch statement.
为了知道Any 或 AnyObject的常量或变量具体是什么类型的,你可以在一个switch语句中使用is或as。下面的例子遍历了things数组,并请求了每一项的类型。
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
NOTE
The Any type represents values of any type, including optional types. Swift gives you a warning if you use an optional value where a value of type Any is expected. If you really do need to use an optional value as an Any value, you can use the as operator to explicitly cast the optional to Any, as shown below.
注意,Any类型表示任意类型的值,包括可选类型。如果你在该用any类型的地方用了可选类型, swift会报一个警告。如果你真的需要使用一个可选类型作为any类型的值,你可以使用as操作符明确地把可选类型转换为any类型:
let optionalNumber: Int? = 3
things.append(optionalNumber) // Warning
things.append(optionalNumber as Any) // No warning
网友评论