[翻译]Swift编程语言——造型

造型

造型是检查一个实例的类型,并且/或者将这个实例作为它所处类继承谱系中的超类或者子类处理 的一种方式。

Swift的造型通过is和as操作符实现。这两个操作符提供了一种简单而且方便的方式检查一个值的类型或者将一个值造型为另外一种类型。

也可以使用操作来检查一个类型是否遵循了一个协议,就像 Checking for Protocol Conformance 一节的描述。

为造型定义一个类的谱系

可以对一个类谱系中的类或者子类采用造型来检查一个特定类实例的类型或者将特定类型的实例造型为谱系中的另外一个类。下面的三个代码片段定义了一个类的谱系和一个包含这些类实例的数组,用作造型的示例。

第一个代码片段定义了一个新的基本类叫做MediaItem。这个类提供了在数字媒体图书馆中存在的任何种类藏品的基本功能。它定义了一个String类型的name属性和一个init name构造方法。(这里假象所有的媒体藏品都,包括了电影和歌曲,都会有一个名字。)

class​ ​MediaItem​ {
​    ​var​ ​name​: ​String
​    ​init​(​name​: ​String​) {
​        ​self​.​name​ = ​name
​    }
​}

接下来的代码片段定义了两个MediaItem的子类。第一个子类Movie,封装了关于电影或者胶片的额外信息。它在MediaItem基础上添加了一个director属性,还有一个和超类吻合的构造方法。第二个子类,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,所以会推断library数组的类型是[MediaItem]:

​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
​    } ​else​ ​if​ ​item​ ​is​ ​Song​ {
​        ++​songCount
​    }
​}
​
​println​(​"Media library contains ​\(​movieCount​)​ movies and ​\(​songCount​)​ songs"​)
​// prints "Media library contains 2 movies and 3 songs"

这个例子中遍历了所有library数组中的内容。每次for-in循环中,会将下数组中的下一个MediaItem赋值给常量item。

如果当前的MediaItem是一个Movie实例,那么item is Movie 返回true,反之返回false。类似的,item is Song 检查当前内容是否是一个Song实例。在for-in循环的末尾,movieCount和songCount包含了每种类型内容在数组中被发现的个数。

向下造型

在后台,一个特定类的常量或者变量可能指向一个这个类子类。如果是这种情况,可以通过造型操作符(type case operator)(as?或者as!)将其造型为子类。

因为向下造型可能会失败,造型操作符有两种不同的方式。可选方式,as?,返回一个可选的想要向下造型的类型。强制方式,as!,尝试将向下造型而且强制拆包结果作为一个单一的复合操作。

当不能确信向下造型一定会成功时,使用可选方式的造型操作符(as?)。可选模式始终会返回一个可选值,如果造型失败返回值将是nil。这样可以检查造型是否成功。

只有当可以确信向下造型一定会成功时,使用强制方式的造型操作符(as!)。当向下造型的目标类型不对时,这种方式会触发一个运行时错误。

下面的例子遍历了library数组中的每个MediaItem,并且将每个内容中的对应描述打印了出来。为了做到这点,需要对每个内容作为Movie或者Song进行访问,而不是作为MeidaItem。内容的描述中用到了它们特有的属性,所以必须要能够访问Movie的director属性或者Song的artist属性。

这个例子中,数组中的每一项,可能是Movie,也可能是Song。你不知道每一项的更多信息,使用可选方式的造型操作符(as?)在每次循环中检查向下造型的做法是合适的:

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

例子一开始是这将当前的item向下造型为Movie。因为item是一个MediaItem实例,所以它可能是个Movie;同样它也可能是个Song,或者只是 一个MediaItem。因为这些不确定性,所以as?方式的造型操作符在试图向下造型为一个子类时返回一个可选值。item as Movie返回一个Movie?或者说是“可选的Movie”。

当碰到liberary书中的一个Song实例时,向下造型为Movie会失败。为了解决这个问题,上面的例子使用了可选绑定来检查可选Movie实际包含的值(其实就是检查向下造型是否成功。)这个可选绑定写作“if let movie = item as? Movie”它的意思是:
“试着将item作为Movie访问。如果成功,用返回的可选Movie中的值给临时常量moive赋值。”

如果造型成功,movie中的属性被用来打印那个Movie实例的描述,其中包括了它的director的名字。当一个Song被找到,同样的规则在检查Song实例时也被使用,也会打印出对应的描述(包括artist名字)。

NOTE
造型实际上没有改变实例也没有改变实例的值。实例仍然是实例,只不过被当作造型的目标类型处理和访问了而已。

对Any和AnyObject造型

Swift提供了两个特殊的类型别称表示没有指定的类型:

AnyObject可以表示任意类的实例。
Any竟然可以表示任意实例,包括函数类型。

NOTE
属实需要使用Any和AnyObject的行为或者功能时才可以使用它们。通常,在代码中指定类型比较好。

任何对象(AnyObject)

在使用Cocoa API的时候,经常会接收到类型是[AnyObject]的数组,或者叫做“一个值是任意对象类型的数组”。这是因为OC语言没有明确类型的数组。但是,经常根据API提供的信息可以确信那个数组中含有某些特定的对象。

这种情况下,可以使用强制版本的造型操作符(as)对数组中的每一项都造型为特定的类型而不再使用AnyObject,这样做不需要可选类型解包。

下面的例子定义了一个[AnyObject]类型的数组,用Movie的三个实例填充了它:

​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)操作符对其直接进行造型和拆包:

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

这个循环的更简洁版本是,将someObjects 数组造型为[Movie]类型而不是对每个内容进行向下造型:

​for​ ​movie​ ​in​ ​someObjects​ ​as​ [​Movie​] {
​    ​println​(​"Movie: '​\(​movie​.​name​)​',dir. Ridley Scott

任何(Any)

这里的例子使用了Any来处理一个不同类型的混合体,其中包括了函数类型和不是类的类型。这个例子创建了一个数组叫做things,它其中存储了Any类型的值:

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

tings数组包含两个Int值、两个Double值、一个String值,一个{Double,Double}类型的元组、电影“Ghostbusters”还有一个带一个String值参数返回另一个String值的臂包表达式。

可以在switch的case语句中使用is和as操作符,从仅仅已知为Any或者AnyObject类型的常量或者变量中发现特定的类型。下面的例子遍历了things数组的每一项,同时用一个switch语句查询每一项的类型。若干个switch的case语句将匹配到的值绑定到特定类型的常量,进而可以将值打印出来:

for​ ​thing​ ​in​ ​things​ {
​    ​switch​ ​thing​ {
​    ​case​ ​0​ ​as​ ​Int​:
​        ​println​(​"zero as an Int"​)
​    ​case​ ​0​ ​as​ ​Double​:
​        ​println​(​"zero as a Double"​)
​    ​case​ ​let​ ​someInt​ ​as​ ​Int​:
​        ​println​(​"an integer value of ​\(​someInt​)​"​)
​    ​case​ ​let​ ​someDouble​ ​as​ ​Double​ ​where​ ​someDouble​ > ​0​:
​        ​println​(​"a positive double value of ​\(​someDouble​)​"​)
​    ​case​ ​is​ ​Double​:
​        ​println​(​"some other double value that I don't want to print"​)
​    ​case​ ​let​ ​someString​ ​as​ ​String​:
​        ​println​(​"a string value of \"​\(​someString​)​\""​)
​    ​case​ ​let​ (​x​,​y​) ​as​ (​Double​,​Double​):
​        ​println​(​"an (x,y) point at ​\(​x​)​,​\(​y​)​"​)
​    ​case​ ​let​ ​movie​ ​as​ ​Movie​:
​        ​println​(​"a movie called '​\(​movie​.​name​)​',dir. ​\(​movie​.​director​)​"​)
​    ​case​ ​let​ ​stringConverter​ ​as​ ​String​ -> ​String​:
​        ​println​(​stringConverter​(​"Michael"​))
​    ​default​:
​        ​println​(​"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

NOTE switch语句中的case使用了强制版本的造型操作符(as,而不是as?)来检查和造型特定的类型。在switch 的case语句上下文中,这样的检查始终是安全的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘贴.待开发的功能:1.支持自动生成约束2.开发设置页面3.做一个浏览器插件,支持不需要下载整个工程,可即时操作当前蓝湖浏览页面4.支持Flutter语言模板生成5.支持更多平台,如Sketch等6.支持用户自定义语言模板
现实生活中,我们听到的声音都是时间连续的,我们称为这种信号叫模拟信号。模拟信号需要进行数字化以后才能在计算机中使用。目前我们在计算机上进行音频播放都需要依赖于音频文件。那么音频文件如何生成的呢?音频文件的生成过程是将声音信息采样、量化和编码产生的数字信号的过程,我们人耳所能听到的声音频率范围为(20Hz~20KHz),因此音频文件格式的最大带宽是20KHZ。根据奈奎斯特的理论,音频文件的采样率一般在40~50KHZ之间。奈奎斯特采样定律,又称香农采样定律。...............
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿遍又亿遍,久久不能离开!看着小仙紫姐姐的蹦迪视频,除了一键三连还能做什么?突发奇想,能不能把舞蹈视频转成代码舞呢?说干就干,今天就手把手教大家如何把跳舞视频转成代码舞,跟着仙女姐姐一起蹦起来~视频来源:【紫颜】见过仙女蹦迪吗 【千盏】一、核心功能设计总体来说,我们需要分为以下几步完成:从B站上把小姐姐的视频下载下来对视频进行截取GIF,把截取的GIF通过ASCII Animator进行ASCII字符转换把转换的字符gif根据每
【Android App】实战项目之仿抖音的短视频分享App(附源码和演示视频 超详细必看)
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至2022年4月底。我已经将这篇博客的内容写为论文,上传至arxiv:https://arxiv.org/pdf/2204.10160.pdf欢迎大家指出我论文中的问题,特别是语法与用词问题在github上,我也上传了完整的项目:https://github.com/Whiffe/Custom-ava-dataset_Custom-Spatio-Temporally-Action-Video-Dataset关于自定义ava数据集,也是后台
因为我既对接过session、cookie,也对接过JWT,今年因为工作需要也对接了gtoken的2个版本,对这方面的理解还算深入。尤其是看到官方文档评论区又小伙伴表示看不懂,所以做了这期视频内容出来:视频在这里:本期内容对应B站的开源视频因为涉及的知识点比较多,视频内容比较长。如果你觉得看视频浪费时间,可以直接阅读源码:goframe v2版本集成gtokengoframe v1版本集成gtokengoframe v2版本集成jwtgoframe v2版本session登录官方调用示例文档jwt和sess
【Android App】实战项目之仿微信的私信和群聊App(附源码和演示视频 超详细必看)
用Android Studio的VideoView组件实现简单的本地视频播放器。本文将讲解如何使用Android视频播放器VideoView组件来播放本地视频和网络视频,实现起来还是比较简单的。VideoView组件的作用与ImageView类似,只是ImageView用于显示图片,VideoView用于播放视频。...
采用MATLAB对正弦信号,语音信号进行生成、采样和内插恢复,利用MATLAB工具箱对混杂噪声的音频信号进行滤波
随着移动互联网、云端存储等技术的快速发展,包含丰富信息的音频数据呈现几何级速率增长。这些海量数据在为人工分析带来困难的同时,也为音频认知、创新学习研究提供了数据基础。在本节中,我们通过构建生成模型来生成音频序列文件,从而进一步加深对序列数据处理问题的了解。
基于yolov5+deepsort+slowfast算法的视频实时行为检测。1. yolov5实现目标检测,确定目标坐标 2. deepsort实现目标跟踪,持续标注目标坐标 3. slowfast实现动作识别,并给出置信率 4. 用框持续框住目标,并将动作类别以及置信度显示在框上
数字电子钟设计本文主要完成数字电子钟的以下功能1、计时功能(24小时)2、秒表功能(一个按键实现开始暂停,另一个按键实现清零功能)3、闹钟功能(设置闹钟以及到时响10秒)4、校时功能5、其他功能(清零、加速、星期、八位数码管显示等)前排提示:前面几篇文章介绍过的内容就不详细介绍了,可以看我专栏的前几篇文章。PS.工程文件放在最后面总体设计本次设计主要是在前一篇文章 数字电子钟基本功能的实现 的基础上改编而成的,主要结构不变,分频器将50MHz分为较低的频率备用;dig_select
1.进入官网下载OBS stdioOpen Broadcaster Software | OBS (obsproject.com)2.下载一个插件,拓展OBS的虚拟摄像头功能链接:OBS 虚拟摄像头插件.zip_免费高速下载|百度网盘-分享无限制 (baidu.com)提取码:6656--来自百度网盘超级会员V1的分享**注意**该插件必须下载但OBS的根目录(应该是自动匹配了的)3.打开OBS,选中虚拟摄像头选择启用在底部添加一段视频录制选择下面,进行录制.
Meta公司在9月29日首次推出一款人工智能系统模型:Make-A-Video,可以从给定的文字提示生成短视频。基于**文本到图像生成技术的最新进展**,该技术旨在实现文本到视频的生成,可以仅用几个单词或几行文本生成异想天开、独一无二的视频,将无限的想象力带入生活
音频信号叠加噪声及滤波一、前言二、信号分析及加噪三、滤波去噪四、总结一、前言之前一直对硬件上的内容比较关注,但是可能是因为硬件方面的东西可能真的是比较杂,而且需要渗透的东西太多了,所以学习进展比较缓慢。因为也很少有单纯的硬件学习研究,总是会伴随着各种理论需要硬件做支撑,所以还是想要慢慢接触理论学习。但是之前总找不到切入点,不知道从哪里开始,就一直拖着。最近稍微接触了一点信号处理,就用这个当作切入点,开始接触理论学习。二、信号分析及加噪信号处理选用了matlab做工具,选了一个最简单的语音信号处理方
腾讯云 TRTC 实时音视频服务体验,从认识 TRTC 到 TRTC 的开发实践,Demo 演示& IM 服务搭建。
音乐音频分类技术能够基于音乐内容为音乐添加类别标签,在音乐资源的高效组织、检索和推荐等相关方面的研究和应用具有重要意义。传统的音乐分类方法大量使用了人工设计的声学特征,特征的设计需要音乐领域的知识,不同分类任务的特征往往并不通用。深度学习的出现给更好地解决音乐分类问题提供了新的思路,本文对基于深度学习的音乐音频分类方法进行了研究。首先将音乐的音频信号转换成声谱作为统一表示,避免了手工选取特征存在的问题,然后基于一维卷积构建了一种音乐分类模型。
C++知识精讲16 | 井字棋游戏(配资源+视频)【赋源码,双人对战】
本文主要讲解如何在Java中,使用FFmpeg进行视频的帧读取,并最终合并成Gif动态图。
在本篇博文中,我们谈及了 Swift 中 some、any 关键字以及主关联类型(primary associated types)的前世今生,并由浅及深用简明的示例向大家讲解了它们之间的奥秘玄机。