目录
- 类型转换
- 检查类型:is
- Downcasting:as
- 类型转换为Any和AnyObject
- 嵌套类型
- 引用嵌套类型(待研究)
- Extensions
- 计算属性
- Initializers
- Methods
- Subscripts
- 嵌套类型
类型转换
您可以将类型转换与类和子类的层次结构一起使用,以检查特定类实例的类型,并将该实例转换为相同层次结构中的另一个类。
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")
]
// the type of "library" is inferred to be [MediaItem]
检查类型:is
使用类型检查运算符(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?)的条件形式。这种形式的运算符将始终返回一个可选值,该值将在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)")
}
}
// 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
- 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")
}
}
// 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
嵌套类型
struct BlackjackCard {
// nested Suit enumeration
enum Suit: Character {
case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"
}
// nested Rank enumeration
enum Rank: Int {
case two = 2, three, four, five, six, seven, eight, nine, ten
case jack, queen, king, ace
struct Values { // enum Rank的嵌套结构
let first: Int, second: Int?
}
var values: Values {
switch self {
case .ace:
return Values(first: 1, second: 11)
case .jack, .queen, .king:
return Values(first: 10, second: nil)
default:
return Values(first: self.rawValue, second: nil)
}
}
}
// BlackjackCard properties and methods
let rank: Rank, suit: Suit
var description: String {
var output = "suit is \(suit.rawValue),"
output += " value is \(rank.values.first)"
if let second = rank.values.second {
output += " or \(second)"
}
return output
}
}
let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
print("theAceOfSpades: \(theAceOfSpades.description)")
// Prints "theAceOfSpades: suit is ♠, value is 1 or 11"
Rank和Suit嵌套在其中BlackjackCard,它们的类型也可以从上下文中推断出来,因此,此实例的初始化能够仅通过其案例名称(.ace和.spades)来引用枚举案例。
引用嵌套类型(待研究)
要在其定义上下文之外使用嵌套类型,要为其名称钱加上所嵌套的类型名称的前缀:
let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
// heartsSymbol is "♡"
Extensions
扩展为现有的类,结构,枚举或协议类型添加了新功能。
- 添加计算实例属性和计算类型属性
- 定义实例方法和类型方法
- 提供新的初始化器
- 定义下标
- 定义和使用新的嵌套类型
- 使现有类型符合协议
extension SomeType {
// new functionality to add to SomeType goes here
}
扩展可以扩展现有类型以使其采用一种或多种协议。要添加协议一致性,请使用与为类或结构编写协议名称相同的方式编写协议名称:
extension SomeType: SomeProtocol, AnotherProtocol {
// implementation of protocol requirements goes here
}
计算属性
扩展可以将计算的实例属性和计算的类型属性添加到现有类型。
extension Double {
var km: Double { return self * 1_000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
print("One inch is \(oneInch) meters")
// Prints "One inch is 0.0254 meters"
let threeFeet = 3.ft
print("Three feet is \(threeFeet) meters")
// Prints "Three feet is 0.914399970739201 meters"
let aMarathon = 42.km + 195.m
print("A marathon is \(aMarathon) meters long")
// Prints "A marathon is 42195.0 meters long"
Initializers
扩展可以向现有类型添加新的初始化器。这使您可以扩展其他类型,以接受自己的自定义类型作为初始化程序参数,或提供未包含在该类型的原始实现中的其他初始化选项。
扩展可以将新的便捷初始化程序添加到类,但是不能将新的指定初始化程序或反初始化程序添加到类。指定的初始化程序和反初始化程序必须始终由原始类实现提供。
struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
}
let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))
extension Rect {
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)
Methods
扩展可以向现有类型添加新的实例方法和类型方法。
extension Int {
func repetitions(task: () -> Void) {
for _ in 0..<self {
task()
}
}
}
3.repetitions {
print("Hello!")
}
// Hello!
// Hello!
// Hello!
Mutating Instance Methods
extension Int {
mutating func square() {
self = self * self
}
}
var someInt = 3
someInt.square()
// someInt is now 9
Subscripts
扩展可以将新的下标添加到现有类型。
extension Int {
subscript(digitIndex: Int) -> Int {
var decimalBase = 1
for _ in 0..<digitIndex {
decimalBase *= 10
}
return (self / decimalBase) % 10
}
}
746381295[0]
// returns 5
746381295[1]
// returns 9
746381295[2]
// returns 2
746381295[8]
// returns 7
746381295[9]
// returns 0, as if you had requested:
0746381295[9]
嵌套类型
扩展可以将新的嵌套类型添加到现有的类,结构和枚举中
extension Int {
enum Kind {
case negative, zero, positive
}
var kind: Kind {
switch self {
case 0:
return .zero
case let x where x > 0:
return .positive
default:
return .negative
}
}
}
func printIntegerKinds(_ numbers: [Int]) {
for number in numbers {
switch number.kind {
case .negative:
print("- ", terminator: "")
case .zero:
print("0 ", terminator: "")
case .positive:
print("+ ", terminator: "")
}
}
print("")
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
// Prints "+ + - 0 - 0 + "