【Swift 3.1】19 - 类型转换 (Type Casting)
自从苹果2014年发布Swift,到现在已经两年多了,而Swift也来到了3.1版本。去年利用工作之余,共花了两个多月的时间把官方的Swift编程指南看完。现在整理一下笔记,回顾一下以前的知识。有需要的同学可以去看官方文档>>。
类型转换是用来检查实例的类型,或在继承链中把实例作为不同的父类或子类的一种方法。
Swift中的类型转换用is
和as
来实现。
为类型转换定义一个类的层次结构 (Defining a Class Hierarchy for Type Casting)
第一个类是MediaItem
。假设所有的媒体项目,包括电影和音乐,并且有名字:
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
第二个类是MediaItem
的子类Movie
。第三个也是MediaItem
的子类:
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)
}
}
最后创建了一个library
数组,包含了两个Movie
实例和三个Song
实例。Swift根据字面值推断出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]
虽然这个数组装的是Movie
和Song
实例,但如果遍历这个数组,取出来的元素是MediaItem
类型,而不是Movie
和Song
类型。为了使用他们的真实类型,我们需要检查他们的类型,或者向下转型。
检查类型 (Checking Type)
使用is
来检查一个实例是否是一个子类类型。如果是一个子类类型,返回true
,否则返回false
。
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"
向下转型 (Downcasting)
一个类型的常量或变量实际上可能是子类的实例类型,我们可以使用as?
或者as!
来向下转型到子类类型。
因为向下转型可能会失败,所以转型运算符有两种类型。as?
返回你想转到的那个类型的可选类型;而as!
如果转型成功,返回你想转到的那个类型,转型失败将会报错。
如果不确定是否能转型成功,使用as?
;如果能确定转型成功,使用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的类型转换 (Type Casting for Any and AnyObject)
Swift提供了两种不确定的类型:
-
Any
可以代表任何类型的实例,包括方法类型 -
AnyObject
代表任何class类型的实例
下面是一个例子:
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")
}
}
// 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
注意: Any
代表任何类型的值,包括可选类型。如果在需要传入Any
类型的位置传入一个可选类型的值,Swift会给你一个警告。如果确实需要把可选类型的值作为一个Any
类型的值,可以使用as
来明确地转为Any
类型:
let optionalNumber: Int? = 3
things.append(optionalNumber) // Warning
things.append(optionalNumber as Any) // No warning
第十九部分完。下个部分:【Swift 3.1】20 - 嵌套类型 (Nested Types)
如果有错误的地方,欢迎指正!谢谢!
网友评论