Swift 中关于”??”操作符
Swift 中关于”??”操作符
Swift 的语法在保证安全和健壮的基础上,又带有很多非常灵活的特性,比如 ?? 操作符就是其中一个。大家可能已经了解它,也可能有些同学不了解它,这里给大家整理了关于这个操作符值得一看的讨论。
?? 操作符简述
在展开讨论之前,我们先来了解这个操作符的作用是什么。这个操作符和 Optional 相关,让我们来看一个例子:
var a:Int?
print(a ?? 2) //2
?? 操作符的左边是一个 Optional 值,右边是一个普通值,它的作用就是,如果左边的 Optional 值为 nil, 那么就使用右边的普通值作为返回值,如果左边的 Optional 不为 nil,则返回左边的 Optional 解包后的值。
比如我们这个例子中,变量 a 的值是 nil,所以 print 语句输出的就是后面的默认值 2。
刚才那个例子,如果不用 ?? 操作符,那么就是这样的逻辑:
print(a == nil ? 2 : a)
让我们来看看 ?? 操作符的定义:
func ??(optional: T?, @autoclosure defaultValue: () throws -> T) -> T
把它简化一下,就是:
func ??(optional: T?, defaultValue: () throws -> T) -> T
它会接受一个 T 类型的 Optional 值,和一个 T 类型的普通值作为默认值, 然后返回一个解包后的 T 类型的值。这个最终返回值是要根据第一个参数是否为空来确定。
?? 操作符的一些讨论
?? 操作符可以让我们更方便的处理 Optional。 但它也存在一些小问题,Swift 的官方邮件组中大家就有讨论。比如这段代码:
func test(x: ((String) -> String)? = nil) {
let qf = { (p:String) -> String in return "tt" }
let fn = x ?? qf
fn("tt")
}
test 函数它接受另外一个 Optional 类型的参数,然后在它内部用 ?? 操作符判断传进来的函数 x 是否为 nil,如果是,则用内部的另外一个函数 qf 来替代它。
初步来看,这样的代码应该没有什么问题,?? 的左边的变量类型是 ((String) -> String)?, 而右边的变量类型是 (String) -> String, 符合 ?? 操作符的定义。
但这段对 ?? 操作符的使用在实际编译的时候报错了。 我们必须把 qf 也声明成 Optional 类型,才可以使用:
let qf:((String) -> String)? = { (p:String) -> String in return "tt" }
let fn = (x ?? qf)!
fn("tt")
这样虽然编译通过了,但却不符合 ?? 操作符的定义了。这次两边都是 Optional 类型,而表达式的返回值也是 Optional。
这时关于 ?? 在 Swift 邮件组中最近的一个讨论,最后的一次回复说这是 Swift 的一个 bug, 将会在 Swift 3.0 版本中修复,这时这个回复的原文:

?? 操作符两边的类型可以不一样
在邮件组里,还有一个讨论,大家可以看一下这段代码:
var a:Int?
print(a ?? "test")
注意哦,左边的 a 是 Int? 类型的, 而右边是一个 String 字符串。 这段代码在目前的 Swift 2.2 编译上是可以编译通过的。
这个话题讨论的比较多,比较合理的一个解释是 Swift 编译器会根据当前表达式所在的场景进行相应的向上转型。
比如作为 print 函数的参数,编译器会将它们都看做 Any 类型,因为 print 函数接受的就是 Any 类型的参数。所以这个语句可以编译通过。
如果这个语句用在这个场景,就会导致编译失败了:
let x = a ?? "test"
这次的场景,是将它的返回值赋值给 x。 但这次编译器就无法确定他们的通用类型,而将他们看做两个不同的类型,这样就导致编译失败了。
同样的,这段代码就可以编译通过:
let x = a ?? NSDate()
按照刚才的逻辑,那么因为后面的类型是 NSDate 它们都可以是 NSObject 的子类,所以编译器将它们都作为 NSObject 的通用类型来处理了。
而上面的那个例子 let x = a ?? "test" 因为后面的字符串是 Swift 中的 String 类型,编译器就无法找到它们的通用父类,就导致失败了。
当然这是目前的讨论和分析结果,大家也可以一起来思考,来讲你的分析与大家交流。
Swift 中关于”??”操作符的更多相关文章
- Swift中的as操作符
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交 ...
- [翻译]理解Swift中的Optional
原文出处:Understanding Optionals in Swift 苹果新的Swift编程语言带来了一些新的技巧,能使软件开发比以往更方便.更安全.然而,一个很有力的特性Optional,在你 ...
- Swift 中范围和区间如何使用?
虽然现在swift语言已经发展到了2.0版了,但是相信很多学习iOS开发的童鞋仍对swift语言存在各种各样的疑问,今天小编将为大家详细介绍swift中的范围和区间,下面我们一起来看看吧. Range ...
- Swift中的Void类型与空元祖表达式
可能有不少Swift开发者会忽略这么一个细节:在Swift中,Void类型其实是一个别名类型,而其真正的类型为(),即一个空元祖(empty tuple)! 这种语言特性给Swift带来了一些比较方便 ...
- Swift Explore - 关于 Swift 中的 isEqual 的一点探索
在我们进行 App 开发的时候,经常会用到的一个操作就是判断两个对象是否相等.比如两个字符串是否相等.而所谓的 相等 有着两层含义.一个是值相等,还有一个是引用相等.如果熟悉 Objective-C ...
- Swift Tips - 在 Swift 中自定义下标访问
Untitled Document.md input[type="date"].form-control,.input-group-sm>input[type="d ...
- Swift中使用构建配置来支持条件编译-b
在Objective-C中,我们经常使用预处理指令来帮助我们根据不同的平台执行不同的代码,以让我们的代码支持不同的平台,如: 1 2 3 4 5 6 7 8 9 #if TARGET_OS_IPHON ...
- 深圳尚学堂:Swift中的“!”和“?”
Swift中的"!"和"?"Swift,苹果于2014年WWDC发布的新开发语言,用于搭建基于苹果平台的应用程序.Swift是一款易学易用的编程语言,而且它还是 ...
- Swift中的"可溢出"算术运算符
大家知道Swift中拥有和C,Objc类似的算术运算符,它们分别是: + - * / % 但是你可能不知道这些Swift中的运算符和C,Objc语言中的有一个很大的不同之处,就是它们不可以被" ...
随机推荐
- 前端自动分环境打包(vue和ant design)
现实中的问题:有时候版本上线的时候,打包时忘记切换环境,将测试包推上正式服务器,那你就会被批了. 期望:在写打包的命令行的时候就觉得自己在打包正式版本,避免推包时候的,不确信自己的包是否正确. 既然有 ...
- javaSystem.out.println()输出byte[]和char[]异常的问题
javaSystem.out.println()输出byte[]和char[]异常的问题 今天 突然有人问我他写的byte[]和char[],在用System.out.println()输出的时候所得 ...
- configparser模块——配置文档
configparser模块用于生成和修改常见配置文档. 预制配置文件:conf.ini [DEFAULT] ServerAliveInterval = 45 Compression = yes Co ...
- 支持触屏的zepto轮播图插件
占个座,有时间再写,呵呵 关于zepto.js,官方标准版是不支持touch的.可以去github下载压缩包,里面有所有支持的模块.我用的zepto.js,是经过打包的,包括polyfill zept ...
- 开发Windows RT平台下的Windows应用商店应用程序的遇到的问题备忘
1. 关于获取Win8开发者许可证的问题: 有一种情况是:如果系统是Win8.0, 那么如果先激活了windows8(用激活工具), 再安装VS2012,那么在新建项目时会提示获取windows8开发 ...
- css 字体样式设置大全
css样式大全(整理版) 字体属性:(font) 大小 {font-size: x-large;}(特大) xx-small;(极小) 一般中文用不到,只要用数值就可以,单位:PX.PD 样式 { ...
- 编译时提示软件包 javax.servlet.http 不存在 import javax.servlet.http.HttpServletRequest;
编译时错误:软件包 javax.servlet.http 不存在import javax.servlet.http.HttpServletRequest; 解决办法:把servlet-api.jar加 ...
- 深度搜索C语言伪代码
bool DFS(Node n, int d){ if (d == 4){//路径长度为返回true,表示此次搜索有解 return true; } for (Node nextNode in n){ ...
- Document flow API in SAP CRM and C4C
Document flow API in CRM 以一个具体的例子来说明.在Appointment的Overview page上能看见一个名叫Reference的区域,这里可以维护一些其他的业务文档的 ...
- 关于TOCTTOU攻击的简介
前言 最近看到了一些以 at 结尾的Linux系统调用,在维基百科上面说这可以防御一些特定的TOCTTOU攻击,而在TOCTTOU对应页面中并没有中文版的介绍,而且百度的结果也比较少,于是决定抽空写一 ...