【Swift 3.1】19 - 类型转换 (Type Casti

2017-01-28  本文已影响142人  Lebron_James

【Swift 3.1】19 - 类型转换 (Type Casting)

自从苹果2014年发布Swift,到现在已经两年多了,而Swift也来到了3.1版本。去年利用工作之余,共花了两个多月的时间把官方的Swift编程指南看完。现在整理一下笔记,回顾一下以前的知识。有需要的同学可以去看官方文档>>


类型转换是用来检查实例的类型,或在继承链中把实例作为不同的父类或子类的一种方法。

Swift中的类型转换用isas来实现。

为类型转换定义一个类的层次结构 (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]

虽然这个数组装的是MovieSong实例,但如果遍历这个数组,取出来的元素是MediaItem类型,而不是MovieSong类型。为了使用他们的真实类型,我们需要检查他们的类型,或者向下转型。

检查类型 (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提供了两种不确定的类型:

下面是一个例子:

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)


如果有错误的地方,欢迎指正!谢谢!

上一篇下一篇

猜你喜欢

热点阅读