热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

swift声明变量的?和!的区别

转载:http:blog.csdn.netgf771115articledetails46819193Swift语言使用var定义变量,但和别的语言不同,

转载:http://blog.csdn.net/gf771115/article/details/46819193

Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量赋初始值,也就是说变量不会有默认值,所以要求使用变量之前必须要对其初始化。如果在使用变量之前不进行初始化就会报错:

var stringValue : String
//error: variable 'stringValue' used before being initialized
//let hashValue = stringValue.hashValue
// ^
let hashValue = stringValue.hashValue


上面了解到的是普通值,接下来Optional值要上场了。经喵神提醒,Optional其实是个enum,里面有NoneSome两种类型。其实所谓的nil就是Optional.None, 非nil就是Optional.Some, 然后会通过Some(T)包装(wrap)原始值,这也是为什么在使用Optional的时候要拆包(从enum里取出来原始值)的原因, 也是PlayGround会把Optional值显示为类似{Some "hello world"}的原因,这里是enum Optional的定义:

enum Optional<T> : LogicValue, Reflectable {case Nonecase Some(T)init()init(_ some: T)/// Allow use in a Boolean context.func getLogicValue() -> Bool/// Haskell&#39;s fmap, which was mis-namedfunc map<U>(f: (T) -> U) -> U?func getMirror() -> Mirror
}


声明为Optional只需要在类型后面紧跟一个?即可。如:

var strValue: String? //?相当于下面这种写法的语法糖
var strValue: Optional<String>



上面这个Optional的声明&#xff0c;意思不是”我声明了一个Optional的String值”, 而是”我声明了一个Optional类型值&#xff0c;它可能包含一个String值&#xff0c;也可能什么都不包含”&#xff0c;也就是说实际上我们声明的是Optional类型&#xff0c;而不是声明了一个String类型&#xff0c;这一点需要铭记在心。


建议再读一遍上段文字。

一旦声明为Optional的&#xff0c;如果不显式的赋值就会有个默认值nil。判断一个Optional的值是否有值&#xff0c;可以用if来判断&#xff1a;

if strValue {//do sth with strValue
}


然后怎么使用Optional值呢&#xff1f;文档中也有提到说&#xff0c;在使用Optional值的时候需要在具体的操作&#xff0c;比如调用方法、属性、下标索引等前面需要加上一个?&#xff0c;如果是nil值&#xff0c;也就是Optional.None&#xff0c;会跳过后面的操作不执行&#xff0c;如果有值&#xff0c;就是Optional.Some&#xff0c;可能就会拆包(unwrap)&#xff0c;然后对拆包后的值执行后面的操作&#xff0c;来保证执行这个操作的安全性&#xff0c;比如&#xff1a;

let hashValue &#61; strValue?.hashValue


strValue是Optional的字符串&#xff0c;如果strValue是nil&#xff0c;则hashValue也为nil&#xff0c;如果strValue不为nil&#xff0c;hashValue就是strValue字符串的哈希值(其实也是用Optional wrap后的值)

另外&#xff0c;?还可以用在安全地调用protocol类型方法上&#xff0c;比如&#xff1a;


&#64;objc protocol Downloadable {&#64;optional func download(toPath: String) -> Bool;
}&#64;objc class Content: Downloadable {//download method not be implemented
}var delegate: Downloadable &#61; Downloadable()
delegate.download?("some path")


因为上面的delegate是Downloadable类型的&#xff0c;它的download方法是optional&#xff0c;所以它的具体实现有没有download方法是不确定的。Swift提供了一种在参数括号前加上一个?的方式来安全地调用protocol的optional方法。

另外如果你需要像下面这样向下转型(Downcast)&#xff0c;可能会用到 as?&#xff1a;

if let dataSource &#61; object as? UITableViewDataSource {let rowsInFirstSection &#61; dataSource.tableView(tableView, numberOfRowsInSection: 0)
}



到这里我们看到了?的几种使用场景:
1.声明Optional值变量
2.用在对Optional值操作中&#xff0c;用来判断是否能响应后面的操作
3.用于安全调用protocol的optional方法
4.使用 as? 向下转型(Downcast)

另外&#xff0c;对于Optional值&#xff0c;不能直接进行操作&#xff0c;否则会报错&#xff1a;

//error: &#39;String?&#39; does not have a member named &#39;hashValue&#39;
//let hashValue &#61; strValue.hashValue
// ^ ~~~~~~~~~let hashValue &#61; strValue.hashValue


上面提到Optional值需要拆包(unwrap)后才能得到原来值&#xff0c;然后才能对其操作&#xff0c;那怎么来拆包呢&#xff1f;拆包提到了几种方法&#xff0c;一种是Optional Binding&#xff0c; 比如&#xff1a;

if let str &#61; strValue {let hashValue &#61; str.hashValue
}


还有一种是在具体的操作前添加!符号&#xff0c;好吧&#xff0c;这又是什么诡异的语法?!

直接上例子&#xff0c;strValue是Optional的String&#xff1a;

let hashValue &#61; strValue!.hashValue


这里的!表示“我确定这里的的strValue一定是非nil的&#xff0c;尽情调用吧” &#xff0c;比如这种情况:

if strValue {let hashValue &#61; strValue!.hashValue
}


{}里的strValue一定是非nil的&#xff0c;所以就能直接加上!&#xff0c;强制拆包(unwrap)并执行后面的操作。 当然如果不加判断&#xff0c;strValue不小心为nil的话&#xff0c;就会出错&#xff0c;crash掉。

考虑下这一种情况&#xff0c;我们有一个自定义的MyViewController类&#xff0c;类中有一个属性是myLabel&#xff0c;myLabel是在viewDidLoad中进行初始化。因为是在viewDidLoad中初始化&#xff0c;所以不能直接声明为普通值&#xff1a;var myLabel : UILabel&#xff0c;因为非Optional的变量必须在声明时或者构造器中进行初始化&#xff0c;但我们是想在viewDidLoad中初始化&#xff0c;所以就只能声明为Optional&#xff1a;var myLabel: UILabel?, 虽然我们确定在viewDidLoad中会初始化&#xff0c;并且在ViewController的生命周期内不会置为nil&#xff0c;但是在对myLabel操作时&#xff0c;每次依然要加上!来强制拆包(在读取值的时候&#xff0c;也可以用?&#xff0c;谢谢iPresent在回复中提醒)&#xff0c;比如:

myLabel!.text &#61; "text"
myLabel!.frame &#61; CGRectMake(0, 0, 10, 10)
...


对于这种类型的值&#xff0c;我们可以直接这么声明&#xff1a;var myLabel: UILabel!, 果然是高(hao)大(gui)上(yi)的语法!, 这种是特殊的Optional&#xff0c;称为Implicitly Unwrapped Optionals, 直译就是隐式拆包的Optional&#xff0c;就等于说你每次对这种类型的值操作时&#xff0c;都会自动在操作前补上一个!进行拆包&#xff0c;然后在执行后面的操作&#xff0c;当然如果该值是nil&#xff0c;也一样会报错crash掉。

var myLabel: UILabel! //!相当于下面这种写法的语法糖
var myLabel: ImplicitlyUnwrappedOptional<UILabel>



那么!大概也有两种使用场景
1.强制对Optional值进行拆包(unwrap)
2.声明Implicitly Unwrapped Optionals值&#xff0c;一般用于类中的属性

Swift是门新生的语言&#xff0c;我们有幸见证了它的诞生&#xff0c;激动之余也在佩服苹果大刀阔斧的推出一个新的语言替代一个已经比较成熟语言的魄力&#xff0c;今天在知乎日报上看到一个回答是说Swift是一门玩具语言&#xff0c;正当想去吐槽&#xff0c;发现回答已经被删除了。个人认为苹果是很认真的推出Swift的&#xff0c;从Swift的各种细微的设计也能看的出来。

另外这两个小符号就花费了我不少的时间来理解&#xff0c;可能依然会有错误和不妥之处&#xff0c;欢迎大家指正&#xff0c;本文旨在抛砖引玉。除此之外&#xff0c;Swift还有很多很棒的特性&#xff0c;WWDC 2014 会有四五个和Swift语言相关的Video&#xff0c;大家也可以去关注一下。

最后要感谢喵神的纠正了多处有问题的地方&#xff0c;thx, have fun!




推荐阅读
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
author-avatar
癫逼
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有