目录

  • 类型转换
  • 检查类型: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 + "