Swift类型转换
关于「类型转换」(Type Casting),《The Swift Programming Language》描述如下:
Type casting is a way to check the type of an instance, and/or to treat that instance as if it is a different superclass or subclass from somewhere else in its own class hierarchy.
在Swift中,有两个关键字与类型转换相关:is和as。前者体现的是Swift的内省机制(introspection),用于检查某个实例的类型(类似于OC中的isKindOfClass:和isMemberOfClass:);后者用于类型转换,即将某个类型实例转换为其父类的实例或者子类的实例。
Swift中的类型转换是一个非常容易理解的概念,本文将以代码为辅助对之进行简单阐述。
首先定义几个类为后文服务:
// 「媒体」类
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")
]
很容易理解,该library的类型是[MediaItem]。站在物理的角度,library中存储的元素要么是Movie类型实例,要么是Song类型实例。但站在逻辑的角度,你若遍历library,则取出的实例会是MediaItem类型的,而不是Movie或者Song。所以,若想让library中的元素基于它们本来的类型处理事情,那么需要检查它们的类型或者向下转换它们的类型到其他类型。
Checking Type
用类型检查操作符is来检查一个实例是否属于特定类型。若实例属于那个类型,类型检查操作符返回true,否则返回false。
如下定义了两个变量,movieCount和songCount,分别用来计算library中Movie和Song类型实例的数量,如下:
var movieCount =
var songCount = for item in library {
if item is Movie {
movieCount++
} else if item is Song {
songCount++
}
} println("Media library contains \(movieCount) movies and \(songCount) songs")
// prints "Media library contains 2 movies and 3 songs"
Downcasting
「Downcasting」常常被翻译为「向下转型」。某个常量或变量在逻辑层面可能属于某种类型,但在物理层面可能属于其某个子类类型。上述library中的元素就是这种情况(逻辑层面包含的元素都属于MediaItem类型,但是实际上有的属于Movie类型,有的属于Song类型)。对于这种情况,你可以使用转换操作符as向下转型(譬如MediaItem转Song或Movie)。
在OC中,类型转换非常简单,譬如:
UIViewController *VC = [[UIViewController alloc] init];
UITableViewController *tableVC = (UITableViewController *)VC;
tableVC.tableView.background = [UIColor whiteColor];
这段代码当然会通过编译,但是会产生runtime错误,至于原因就不啰嗦了。
对于Swift也一样,downcasting也可能会失败。不同的是,在OC中,类型转换成功或失败是无法获知的(因为人家是动态语言嘛,类型检测在runtime才会进行);Swift是强类型语言,类型转换成功与否是可以检查到的,简单来说,Swift的downcasting会返回一个optional,若失败了,则该optional的值为nil;
类型转换操作符有两种不同形式:
as?,返回一个optional,若转换成功,则包含你期待的类型实例,若失败,则是nil;as!,相当于转换后强制解包,若转换失败,则会造成runtime错误;
显然,当你不确定是否能转换是否成功时,使用as?;否则,使用as!。
P.S:能不能直接使用as?No!
下面的示例遍历了上文的library常量,并打印出其中所有元素的描述信息(名字,音乐作者或者电影导演),如下:
for item in library {
if let movie = item as? Movie {
println("Movie: '\(movie.name)', dir. \(movie.director)")
} else if let song = item as? Song {
println("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 and AnyObject
虽然Swift是强类型语言,但是OC不是啊,譬如OC中数组可以存放允许类型的类对象(不要求类型一致);考虑到兼容性,Swift为不确定类型提供了两种特殊类型:
AnyObject可以代表任何类类型的实例;Any可以表示任何类型实例,包括方法/函数类型;
值得一提的是,AnyObject和Any尽可能少用,毕竟类型越清晰越好,Swift文档是这么描述的:
Use
AnyandAnyObjectonly when you explicitly need the behavior and capabilities they provide. It is always better to be specific about the types you expect to work with in your code.
AnyObject
使用Cocoa APIs时,常常会接收到一个[AnyObject]类型的数组,或者说「一个任何对象类型的数组」。这是因为OC没有明确的类型化数组。然而,很多时候我们常常可以确定知道包含在数组(获取其他集合)中元素的确切类型;在这种情况下,可以使用as!来向下对元素类型进行转换(转到比AnyObject更确切的类型)。如下是对AnyObject向下转型的一个栗子:
let someObjects: [AnyObject] = [
Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
Movie(name: "Moon", director: "Duncan Jones"),
Movie(name: "Alien", director: "Ridley Scott")
]
因为知道这个数组只包含Movie实例,你可以直接用as!向下转型并解包到Movie类型:
for object in someObjects {
let movie = object as! Movie
println("Movie: '\(movie.name)', dir. \(movie.director)")
}
/*输出:
Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
Movie: 'Moon', dir. Duncan Jones
Movie: 'Alien', dir. Ridley Scott
*/
还有一种更简洁的写法:
for movie in someObjects as! [Movie] {
println("Movie: '\(movie.name)', dir. \(movie.director)")
}
Any
Any和AnyObject差不多,只是后者仅限于类类型,前者通吃所有类型。比较简单,这里不赘述了。
Swift类型转换的更多相关文章
- Swift - 类型转换(as as! as?)
swift 类型转换 一,as 1,as使用场合 (1)从派生类转换为基类,向上转型(upcasts) class Animal {} class Cat: Animal {} let cat = C ...
- swift:类型转换(is用作判断检测、as用作类型向下转换)
类型转换是一种检查类实例的方式,并且哦或者也是让实例作为它的父类或者子类的一种方式. 类型转换在Swift中使用is 和 as操作符实现.这两个操作符提供了一种简单达意的方式去检查值的类型或者转换 ...
- Swift类型转换 和 类型别名的定义(typealias)
(一)类型转换 类型转化在 Swift 中是比较严格的,不同类型之间可以认为是不能相互转化的,只能重新产生一个对象和值,并拷贝一份. 1.0 整型数值之间的转换. // 不同类型是不能直接相加的,这时 ...
- Swift 类型转换
1.类型转换 1.1 隐式类型转换 如 C 语言的类型转换 1.2 显式类型转换 Swift 语言是一种强类型语言,其整型的强制类型转换就是调用了参数类型对应的整形扩展构造方法,然后通过对应扩展构造方 ...
- swift类型转换之Could not cast value of type xxx to xxx错误的一种特殊情况记录
之前swift项目打包成Framework静态库,提供给OC项目套入使用时,有时会抱这样一个错误: 这个错误发生的概率比较随机,有时会,有时不会,而且这句话在swift中的使用,是做model类型强制 ...
- OC与Swift的区别二(常量、变量、运算符)
4.常量与变量声明 oc的变量声明使用 类型 变量名 = 变量值的方式,其中类型为系统内置数据类型或自定义类型,变量名需由英文字母开头且不能包含特殊字符 swift变量声明使用 var 变量名 = ...
- 【译】Swift 字符串速查表
[译]Swift 字符串速查表 2015-12-18 10:32 编辑: suiling 分类:Swift 来源:CocoaChina翻译活动 10 5585 Swift字符串 招聘信息: iOS高级 ...
- iOS核心动画高级技巧之图层变换和专用图层(二)
iOS核心动画高级技巧之CALayer(一) iOS核心动画高级技巧之图层变换和专用图层(二)iOS核心动画高级技巧之核心动画(三)iOS核心动画高级技巧之性能(四)iOS核心动画高级技巧之动画总结( ...
- swift中文文档- 类型转换
未翻译完 待续(英语烂,求斧正) Type Casting 类型转换 Type casting is a way to check the type of an instance, and/or to ...
随机推荐
- scrapy 启动失败,scrapy startproject test 出错 'module' object has no attribute 'OP_NO_TLSv1_1
你先看看 pip install scrapy需要的 pyopenssl twisted 等和你安装的版本一样么 我的就是因为TWist 版本高于 需要的 用pip install twist ...
- VS中的 MD/MT设置 【转】
VS系列工具作为目前微软主打的集成开发环境,在历经了近20多年的发展后,到如今已经可以 说是Windows平台上各种IDE环境中的翘楚了.很多别的开发工具已经难望其项背了,如今VS2010也已经面市很 ...
- 千呼万唤始出来:ArchLinux for Espressobin
前言 原创文章,转载引用务必注明链接,水平有限,如有疏漏,欢迎指正. 本文使用Markdown写成,为获得更好的阅读体验和正常的链接.图片显示,请访问我的博客原文: http://www.cnblog ...
- Android的logger机制分析
分析安卓的Logger机制 一.概述 Logger机制是在Android系统中提供的一个轻量级的日志系统,这个日志系统是以驱动程序的形式在内核空间实现的,在用户空间分别提供了Java接口和C/C++接 ...
- cas 单点登录(SSO)之中的一个: jasig cas-server 安装
cas 单点登录(SSO)实验之中的一个: jasig cas-server 安装 參考文章: http://my.oschina.net/indestiny/blog/200768#comments ...
- C语言-多重背包问题
多重背包问题 问题:有N种物品和一个容量为V的背包.第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大. 分 ...
- 2014年8月25日,收藏家和杀手——面向对象的C++和C(一)
近期事情特别多,睡眠也都非常晚,有点精神和身体混乱的感觉,所以想写写技术分析文章.让两者的我都调整一下.这篇技术分析文章是一直想写的,当前仅仅是开篇,有感觉的时候就写写,属于拼凑而成,兴许的篇章没有时 ...
- java 堆和栈一般理解
栈与堆都是Java用来在Ram中存放数据的地方.与C++不同.Java自己主动管理栈和堆.程序猿不能直接地设置栈或堆. Java的堆是一个执行时数据区,类的(对象从中分配空间.这些对象通过new.n ...
- java_类型强转
class Father{ public void fromFather(){ System.out.println("fromFather"); } } interface in ...
- 二维码、条形码扫描——使用Google ZXing
我在项目中用到了二维码扫描的技术,用的是Google提供的ZXing开源项目,它提供二维码和条形码的扫描.扫描条形码就是直接读取条形码的内容,扫描二维码是按照自己指定的二维码格式进行编码和解码. 可以 ...