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 ...
随机推荐
- 自己写的通过ADO操作mysql数据库
#include <iostream> #include <windows.h> #include <atlstr.h> #import "c:\Prog ...
- Django小项目练习
Django学生管理系统 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^class_list/', views.class_list ...
- angular 指令封装弹出框效果
就直接用bs的警告框啦~,Duang~ 功能 可以设置message和type,type就是bs内置的几种颜色 默认提示3秒框自动关闭,或者点击x号关闭 代码 模板 <div class=&qu ...
- cubietruck制作刷新lubuntu-kernel
一:安装交叉编译工具链以及相应的工具(系统最好是ubutnu-64位-server) sudo apt-get install g++ sudo apt-get install libncurses5 ...
- (转)MongoDB在mongo控制台下的基本使用命令
成功启动MongoDB后,再打开一个命令行窗口输入mongo,就可以进行数据库的一些操作. 输入help可以看到基本操作命令: show dbs:显示数据库列表 show collections:显示 ...
- public,protected,private,static,final的区别(转载)
1.类 (1)在java中有public.protected.private三种显示的修饰符用于控制可见性,package不是显示的修饰符,它是隐含的,即如果在类.变量等前没加显示的可见性修饰符,那它 ...
- SAM4E单片机之旅——9、UART与MCK之MAINCK
为得到更高的带宽,需要使用更高的波特率.UART波特率的计算已经介绍过了,现在就尝试下调整外设的时钟频率.可以有多种方法调整外设时钟(MCK)的频率,这里先介绍先主要时钟(MAINCK)的设置,其中包 ...
- go echo studygolang ___go_build_myT_go__1_.exe
https://github.com/studygolang/studygolang [stat]; 用户在线数据存到哪里:redis -> 表示存入 redis,这样支持多机部署; onlin ...
- Ubuntu Firefox没有声音的解决方案
安装ubuntu-restricted-extras sudo apt-get install ubuntu-restricted-extras 参考博文:解决ubuntu中firefox没有声音的问 ...
- 谷歌浏览器使用SelectorGadget和Xpath Helper获取xpath和css path
在上篇文章里,介绍了如何在火狐浏览器中获取网页元素的xpath和css path. 这篇文章将介绍,在谷歌浏览器中使用SelectorGadget和Xpath Helper实现同样功能. 这两个谷歌浏 ...