★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/) ➤GitHub地址:https://github.com/strengthen/LeetCode ➤原文地址:https://www.cnblogs.com/strengthen/p/9739734.html ➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。 ➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创! ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
热烈欢迎,请直接点击!!!
进入博主App Store主页,下载使用各个作品!!!
注:博主将坚持每月上线一个新app!!!
类型转换是一种检查实例类型或将该实例视为与其自身类层次结构中其他位置不同的超类或子类的方法。
Swift中的类型转换是使用is andas 运算符实现的。这两个运算符提供了一种简单而富有表现力的方式来检查值的类型或将值转换为其他类型。
您还可以使用类型强制转换来检查类型是否符合协议,如检查协议一致性中所述。
定义类型转换的类层次结构
您可以将类型强制转换与类和子类的层次结构一起使用,以检查特定类实例的类型,并将该实例强制转换为同一层次结构中的另一个类。下面的三个代码段定义了类的层次结构和包含这些类的实例的数组,以供类型转换示例使用。
第一个代码段定义了一个称为的新基类MediaItem 。此类为出现在数字媒体库中的任何种类的项目提供基本功能。具体来说,它声明name 类型为type的属性String 和初始化程序。(假设所有媒体项目(包括所有电影和歌曲)都将具有名称。)init name
- class MediaItem {
- var name: String
- init(name: String) {
- self.name = name
- }
- }
下一个代码段定义的两个子类MediaItem 。第一个子类Movie 封装有关电影或电影的其他信息。它director 在基MediaItem 类的顶部添加一个属性,并带有一个相应的初始化程序。第二个子类,在基类的顶部Song 添加了一个artist 属性和初始化程序:
- 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 实例。library 通过使用数组文字的内容对其进行初始化来推断数组的类型。Swift的类型检查器能够推导该类型Movie 并Song 具有的公共超类MediaItem ,因此可以[MediaItem] 为library 数组推断类型:
- 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]
存储在其中的项目library 仍然是静止的,Movie 并且是Song 后台的实例。但是,如果您遍历此数组的内容,则返回的项将键入为MediaItem ,而不是Movie 或Song 。为了使用它们作为其本机类型,您需要检查它们的类型,或将它们向下转换为其他类型,如下所述。
检查类型
使用类型检查运算符(is )检查实例是否属于某个子类类型。类型检查运算符返回true 实例是否属于该子类类型,false 如果不是。
下面的例子定义两个变量,movieCount 并且songCount ,其计数的数量Movie 和Song 实例中library 阵列:
- 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"
此示例遍历library 数组中的所有项目。每次遍历时,for -in 循环都将item 常量设置MediaItem 为数组中的下一个常量。
item is Movie true 如果当前MediaItem 是Movie 实例,false 则返回,如果不是,则返回。同样,检查项目是否为实例。在-循环的末尾,和的值包含找到每种类型的实例数的计数。item is Song Song for in movieCount songCount MediaItem
垂头丧气
某个类类型的常量或变量实际上可能是指幕后子类的实例。如果您认为是这种情况,则可以尝试使用类型转换运算符(as? 或as! )将其转换为子类类型。
由于向下转换可能会失败,因此类型转换运算符采用两种不同的形式。条件格式会as? 返回您要向下转换的类型的可选值。强制形式as! 尝试向下转换并强制将结果作为单个复合动作展开。
as? 当您不确定向下转换是否成功时,请使用类型转换运算符()的条件形式。这种形式的运算符将始终返回一个可选值,并且该值将在nil 无法向下转换的情况下返回。这使您可以检查下调是否成功。
as! 仅在确定向下转换将始终成功时,才使用类型转换运算符()的强制形式。如果您尝试向下转换为不正确的类类型,则此形式的运算符将触发运行时错误。
下面的示例对中的每个MediaItem 进行迭代library ,并为每个项目打印适当的描述。为此,它需要以trueMovie 或的方式访问每个项目Song ,而不仅仅是访问a MediaItem 。为了使它能够访问的director 或artist 属性,Movie 或Song 在说明书中使用它,这是必需的。
在此示例中,数组中的每个项目可能是Movie ,也可能是Song 。您事先不知道要为每个项目使用哪个实际类,因此每次使用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
该示例首先尝试将当前值向下转换item 为Movie 。因为item 是一个MediaItem 实例,所以它可能是Movie ; 同样,它也可能是一个Song ,甚至仅仅是一个base MediaItem 。由于存在这种不确定性,当尝试向下转换为子类类型时,类型转换as? 运算符的形式将返回一个可选值。的结果为类型,或“可选”。item as? Movie Movie? Movie
Movie 当应用于Song 库阵列中的实例时,向下转换失败。为了解决这个问题,上面的示例使用可选绑定来检查可选对象是否Movie 实际包含一个值(即,查找向下转换是否成功。)此可选绑定被写为“ ”,可以表示为:if let movie = item as? Movie
“尝试访问item 的Movie 。如果成功,则将一个新的临时常量设置为movie 存储在返回的optional中的值Movie 。”
如果向下转换成功,movie 则使用的属性来打印该Movie 实例的描述,包括其名称director 。使用类似的原理检查Song 实例,并在库中找到artist a时打印适当的描述(包括名称)Song 。
笔记
投射实际上并不会修改实例或更改其值。基础实例保持不变;只需将其视为已强制转换为该类型的实例并进行访问即可。
对Any和AnyObject进行类型转换
Swift提供了两种用于处理非特定类型的特殊类型:
-
Any 可以代表任何类型的实例,包括函数类型。
-
AnyObject 可以代表任何类类型的实例。
使用Any 和AnyObject 只有当你明确需要的行为和能力,他们提供的。最好对要在代码中使用的类型进行具体说明。
这是一个Any 用于混合使用不同类型(包括函数类型和非类类型)的示例。该示例创建一个名为的数组things ,该数组可以存储type的值Any :
- 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)" })
该things 数组包含两个Int 值,两个Double 值,一个String 值,一个类型的元组,电影“ Ghostbusters”,以及一个闭包表达式,该闭包表达式使用一个值并返回另一个值。(Double, Double) String String
要发现一个常量或变量,只知道的是类型的特定类型Any 或AnyObject ,你可以使用一个is 或as 一个模式switch 语句的情况。下面的示例遍历things 数组中的项目,并使用switch 语句查询每个项目的类型。switch 语句的几种情况都将其匹配值绑定到指定类型的常量,以使其值能够被打印:
- 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
|
请发表评论