跳转至

2.5: 类型转换

类型转换简介

类型转换这里主要包含两个概念:

  • 某个实例是否是某种类型
  • 根据继承关系,将某个对象转换成它的父类或其他子类

类型转换使用了两个操作符:

  • is操作符(类型检查)
  • as操作符(类型转换)

定义父类与子类用于类型转换

以下示例代码来自: swift.type_casting

  • 定义基类MediaItem
class MediaItem {
    var name: String  // 包含name属性
    init(name: String) { // init函数
        self.name = name
    }
}
  • 定义子类MovieSong
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实例。根据类型推断规则,这两个实例用于共同的父类MediaItem,所以 这里数组会被推断为[MediaItem]类型,相当于let library:[MediaItem] = [xxx]

let library = [
    Movie(name:"Casablanca", director: "Michael Curtiz"),
    Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
    Movie(name: "Citizen Kane", director: "Orson Welles")
]

类型检查

使用is操作符来检查一个实例能否转换成相应的子类类型。

var movieCount = 0
var songCount = 0
for item in library {
    // 执行向下类型转换,判断是否是Movie类型
    // 对于熟悉C++的人而言,是动态类型转换
    if item is Movie { 
        movieCount += 1
    } else if item is Song { // 判断是否是Song类型
        songCount += 1
    }
}

print("Media library contains: \(movieCount) movies and \(songCount) songs")

向下类型转换

在类的继承关系图中,通常将子类放在父类下面,所以通过将父类向子类的转换称为 向下类型转换。

      +------------+
      | base class |
      +------------+
            |
            |
            |
           \|/
      +------------+
      | subclass   |
      +------------+ 

通过使用(as?)或(as!)来实现向下类型转换。

使用as?执行向下类型转换时,会返回Optional类型,当向下类型转换失败的时候, 会返回nil值。

使用as!来执行向下类型转换时,如果类型转化失败,会触发runtime error.

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)")
    }
}