文档章节

初探swift语言的学习笔记二(可选类型?和隐式可选类型!)

法斗斗
 法斗斗
发布于 2016/03/03 11:18
字数 2191
阅读 10
收藏 0
点赞 1
评论 0

作者:fengsh998
原文地址:http://blog.csdn.net/fengsh998/article/details/28904115

可选类型、隐式可选类型

swift中,可选类型其根源是一个枚举型,里面有None和Some两种类型。其实所谓的nil就是Optional.None, 非nil就是Optional.Some, 然后会通过Some(T)包装(wrap)原始值,这也是为什么在使用Optional的时候要拆包(从enum里取出来原始值)的原因, 也是PlayGround会把Optional值显示为类似{Some "hello world"}的原因,这里是enum Optional的定义:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. enum Optional<T> : LogicValue, Reflectable {  
  2.     case None  
  3.     case Some(T)  
  4.     init()  
  5.     init(_ some: T)  
  6.   
  7.     /// Allow use in a Boolean context.  
  8.     func getLogicValue() -> Bool  
  9.   
  10.     /// Haskell's fmap, which was mis-named  
  11.     func map<U>(f: (T) -> U) -> U?  
  12.     func getMirror() -> Mirror  
  13. }  


语法使用“?”操作符及"!"号操作符

如:“var optionalString: String? = "Hello"
optionalString == nil
 
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}”

大家把optionalName改为nil时看一下会有什么结果?按照理解,应该是? = 后的为可选值,即当我们的的变量为nil时,这里如果有?=操作,则会使用?=后的值作为默认值,而不会为nil. 这个等有环境时,验证一下。

经验证:

分别执行:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var optional :String? = "ok good";//注意?与=号之间有空格?号紧贴最后一个字母不能有空格  
  2. println(optional)  

输出为:

ok good

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var optional :String?//注意?与=号之间有空格?号紧贴最后一个字母不能有空格  
  2. println(optional)  

输出为:

nil


来看下!号,官方释为隐式解包:主要用在一个变量/常量在定义瞬间完成之后值一定会存在的情况。这主要用在类的初始化过程中。

官风例子:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. let possibleString: String? = "An optional string."  
  2. println(possibleString!) // requires an exclamation mark to access its value  
  3. // prints "An optional string."  
  4.   
  5. let assumedString: String! = "An implicitly unwrapped optional string."  
  6. println(assumedString) // no exclamation mark is needed to access its value  

实说话,你照这个例子运行,还真看不出什么,得不出什么结论。因此我自己Z磨着,试着理解一个英文翻译。再自己操刀练习。得出下面的一些结论。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var optionVariables:String? //?相当于下面这种写法的语法糖  
  2. //var optionVariables : Optional<Int>  
  3. let value = optionVariables?.hashValue  
  4. /* 
  5. optionVariables是可选类型的字符串,如果optionVariables是nil,则hashValue也为nil 
  6. 如果optionVariables不为nil,hashValue就是strValue字符串的哈希值 
  7. 到这里我们看到了?的两种使用场景: 
  8. 1.声明Optional值变量 
  9. 2.用在对Optional值操作中,用来判断是否能响应后面的操作 
  10. */  
  11.   
  12. //对于可选类型变量,不能直接进行操作,否则会报错  
  13. //let hashval = optionVariables.hashValue //'String?' does not have a member named 'hashValue'  
  14. //因此要访问值就需要解包,解包有两种  
  15. //第一种:使用if let/var xxx =   
  16. if let hv = optionVariables  
  17. {  
  18.     //run ok;  
  19. }  
  20.   
  21. //第二种:使用!号  
  22. let hv = optionVariables!.hashValue  
  23.   
  24. //这里的!表示“我确定这里的的strValue一定是非nil的,尽情调用吧” ,比如这种情况:  
  25.   
  26. if optionVariables {  
  27.     let hashv = optionVariables!.hashValue  
  28. }  
  29. //{}里的optionVariables一定是非nil的,所以就能直接加上!,强制拆包(unwrap)并执行后面的操作  


凡在变量或常量后加上?的都是一个可选变量/可选常量
凡在变量或常量后加上!的都是隐式可选变量/常量,有点难理解,首先该变量或常量满足可选类型,其主要是可被当生一般的变量/常量来使用,而不需要每次都验证是否有值。

注:如果一个隐式解包的可选类型不包含一个实际值,那么对它的访问会抛出一个运行时错误。在变量/常量名后面加!的情况也是一样的。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var possibleString: String? = "An optional string."  
  2. //possibleString = nil  
  3. println(possibleString) // possibleString 为可选变量,需要使用!来访问的值  
分析:首先 possibleString 因后面带上了?说明这是一个可选的,同时前面加上var为变量,所以这是一个可选类型的变量。其可选值为 "An optional string." 再来看执行println后,可以看出输出为 An optional string. 这点很明显。再来看一下把println这句改一下改为 (即在可选变量后面加上一个!号。)
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">println(possibleString!) // possibleString 为可选变量,需要使用!来访问的值</span>  
这里结果与没有加!号时是完全一样的,输出为An optional string. 

好,现在重点来了,这是很关键的一个测试。把possibleString = nil 这句注释放开让其动行,再分别来看一下println带!和不带!的情况:

情况一:不带!号时,输出为nil .

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">        var possibleString: String? = "An optional string."  
  2.         possibleString = nil  
  3.         println(possibleString) </span>  
情况二:再来看一下带!号
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">        var possibleString: String? = "An optional string."  
  2.         possibleString = nil  
  3.         println(possibleString!) // possibleString 为可选变量,需要使用!来访问的值</span>  
这时运行到这句println就会crash了。会报

fatal error: Can't unwrap Optional.None

错误。 

在情况一时,为什么不会报错,是因为这是一个可选变量当变量为nil时,自动验证是否有可选的值,有则使用可选值,在情况二,加上!访问符来访问possibleString 变量,但由于possibleString设为了nil (等价于var possibleString: String?) 其并没有包含一个实际值,所以抛异常.同样对于下面使用!号来声明的也一样道:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">        var assumedString: String! = "An implicitly unwrapped optional string."  
  2.         assumedString = nil  
  3.         println(assumedString!)</span>  
同样会报:fatal error: Can't unwrap Optional.None

如果你定义了一个可选类型并且没有给予初始值的时候,会默认设置为nil
var surveyAnswer: String? // 初自动设置为nil
注: Swift 的nil不同于Object-C中的nil. Object-C中,nil是一个指针指向不存在的对象。Swift中,nil不是指针而是一个特定类型的空值。任何类型的可选变量都可以被设为nil,不光是指针。

在swift中作何变量/常量的声明都必须带有初始值,否则就要声明为可选型。

即var btn:UIButton 这样是编译报错的。因些必须改为带初始化的如:

var btn2 :UIButton = UIButton()

或者使用? 和! 来约束。

因此常常声明可选或隐式可选变量如:

var btn :UIButton?      // 默认btn = nil

var edt :UITextField!  // 默认edt = nil

至于什么时候使用?什么情况下使用!号来约束变量,我还没有悟出真真原理。

因此借助于自己的几次验证来帮助大家理解。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">        var btn  :UIButton?      // 默认btn = nil  
  2.         var btn2 :UIButton = UIButton()    // 默认实例化一个对对象  
  3.         var btn3 :UIButton!     // 默认btn = nil  
  4.         //var btn4 :UIButton    //编译期报错 要求进行初始化操作  
  5.         //运行会报错fatal error: Can't unwrap Optional.None 因btn = nil  
  6.         btn!.tintColor = UIColor.blackColor()  
  7.         btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  8.         btn!.frame = CGRectMake(0,0,50,40)  
  9.           
  10.         //运行正常  
  11.         btn2.tintColor = UIColor.blackColor()  
  12.         btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  13.         btn2.frame = CGRectMake(0,0,50,40)  
  14.           
  15.         //运行会报错fatal error: Can't unwrap Optional.None 因btn3 = nil  
  16.         btn3.tintColor = UIColor.blackColor()  
  17.         btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  18.         btn3.frame = CGRectMake(0,0,50,40)</span>  

因此为了运行期不crash可以改为如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">        var btn  :UIButton?      // 默认btn = nil  
  2.         var btn2 :UIButton = UIButton()    // 默认实例化一个对对象  
  3.         var btn3 :UIButton!     // 默认btn = nil  
  4.           
  5.         //运行会报错fatal error: Can't unwrap Optional.None 因btn = nil  
  6.         if var tmpbtn = btn  
  7.         {  
  8.             btn!.tintColor = UIColor.blackColor()  
  9.             btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  10.             btn!.frame = CGRectMake(0,0,50,40)  
  11.         }  
  12.           
  13.         //运行正常  
  14.         btn2.tintColor = UIColor.blackColor()  
  15.         btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  16.         btn2.frame = CGRectMake(0,0,50,40)  
  17.           
  18.         //运行会报错fatal error: Can't unwrap Optional.None 因btn3 = nil  
  19.         if var tmpbtn = btn  
  20.         {  
  21.             btn3.tintColor = UIColor.blackColor()  
  22.             btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  23.             btn3.frame = CGRectMake(0,0,50,40)  
  24.         }</span>  
或者

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">        var btn  :UIButton?      // 默认btn = nil  
  2.         var btn2 :UIButton = UIButton()    // 默认实例化一个对对象  
  3.         var btn3 :UIButton!     // 默认btn = nil  
  4.           
  5.         //运行会报错fatal error: Can't unwrap Optional.None 因btn = nil  
  6.         if btn  
  7.         {  
  8.             btn!.tintColor = UIColor.blackColor()  
  9.             btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  10.             btn!.frame = CGRectMake(0,0,50,40)  
  11.         }  
  12.           
  13.         //运行正常  
  14.         btn2.tintColor = UIColor.blackColor()  
  15.         btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  16.         btn2.frame = CGRectMake(0,0,50,40)  
  17.           
  18.         //运行会报错fatal error: Can't unwrap Optional.None 因btn3 = nil  
  19.         if btn3  
  20.         {  
  21.             btn3.tintColor = UIColor.blackColor()  
  22.             btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  23.             btn3.frame = CGRectMake(0,0,50,40)  
  24.         }</span>  
注:如果一个可选类型存在没有值的可能的话,不应该使用解包(隐式)可选类型。这种情况下,一定要使用正常的可选类型。

这句话我个人是这样理解的,如var view:UIView。当我的整个应用中或整个类中不可能存在view = nil的情况时可以设置为var view:UIView! 否则就可声明为var view:UIView?

© 著作权归作者所有

共有 人打赏支持
法斗斗
粉丝 20
博文 336
码字总数 6335
作品 0
杨浦
程序员
Swift笔记-让你2小时学会Swift

过年不能闲着,一边学习Swift,一边写笔记,相信在有一定其他语言基础的情况下用1.5小时看完该文章即可掌握。然后再花30分钟打开XCode写个Demo. 生命中拿出2小时来认识一门语言,很值吧! 笔...

程序员孟帅 ⋅ 2016/02/10 ⋅ 20

重读 Swift 之一:Optional(可选型)

之前学习 Swift 的时候都是比较破碎,零零散散,以至于有些地方学习的不够透彻。所以趁最近有时间,就开始重新学习 Swift ,从最基本的开始学习,希望能深入理解,见微知著! 关于 Swift 我们...

HenryCheng ⋅ 2016/08/05 ⋅ 0

Swift中?和!的区别

1.常量和变量 Swift语言中是用let来定义常量,并且要初始化。var来定义变量,在let或者var后面申明类型,冒号+空格,然后再加上类型名称 2.optional(可选)变量可选变量用于处理值缺失的情况,...

evil_01 ⋅ 2016/05/19 ⋅ 0

Swift 4.0 基础学习总结(一)

Swift简介 作者:Chris Lattner Swift 2010年7月开始设计,1年时间完成基本架构,经历4年开发期于WWDC 2014 苹果2014年开发者大会发布,用于撰写OS X和iOS应用程序。 特点: 语法简单,代码简...

xx_cc ⋅ 2017/11/20 ⋅ 0

10-Swift中的可选类型

swift中的可选类型 注意: 可选类型时swift中非常难理解的一个知识点 暂时先了解,多利用Xcode的提示来使用 随着学习的深入,慢慢理解其中的原理和好处 概念: 在OC开发中,如果一个变量暂停不使用...

不孤独的美食家 ⋅ 2016/08/08 ⋅ 0

The Swift Programming Language

基础部分(The Basics) 1.0 翻译:numbbbbb, lyuka, JaySurplus 校对:lslxdx 2.0 翻译+校对:xtymichael 2.1 翻译:Prayer 校对:shanks,overtrue本页包含内容: 常量和变量声明常量和变量...

Align ⋅ 2016/01/12 ⋅ 0

《从零开始学Swift》学习笔记(Day 27)——可选类型

原创文章,欢迎转载。转载请注明:关东升的博客 可选类型: 我们先看看如下代码: var n1: Int = 10n1 = nil //编译错误 let str: String = nil //编译错误 Int和String类型不能接受nil的,但...

智捷课堂 ⋅ 2015/10/26 ⋅ 0

【Swift4.0】可选类型

翻译能力有限,如有不对的地方,还请见谅!希望对Swift的学习者有所帮助,使用的编写工具:JQNote InNote(iPhone) 在一个值可能缺失的情况下,你可以使用可选类型。一个可选类型代表两种可能...

JackYan0927 ⋅ 2017/12/18 ⋅ 0

Swift 个人学习笔记 - 09: 属性

本文章纯粹是中文版《The Swift Programming Language》的学习笔记,所以绝大部分的内容都是文中有的。本文是本人的学习笔记,不是正式系统的记录。仅供参考 以下还是有很多没看懂、不确定的...

amc ⋅ 2017/03/25 ⋅ 0

iOS开发系列--Swift 3.0

概述 从写第一篇Swift文章的时候到现在Swift已经从1.2发展到了今天的3.0,这期间由于Swift目前还在发展阶段并不能向下兼容,因此第一篇文章中的部分代码在当前的Xcode环境中已经无法运行。在...

jianxin160 ⋅ 2016/06/17 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Docker Swarm的前世今生

概述 在我的《Docker Swarm集群初探》一文中,我们实际体验了Docker Swarm容器集群技术的魅力,与《Kubernetes实践录》一文中提到的Kubernetes集群技术相比,Docker Swarm没有Kubernetes显得...

CodeSheep ⋅ 今天 ⋅ 0

骰子游戏代码开源地址

因为阿里云现在服务器已经停用了,所以上面的配置已经失效。 服务端开源地址:https://gitee.com/goalya/chat4.git 客户端开源地址:https://gitee.com/goalya/client4.git 具体运行界面请参考...

算法之名 ⋅ 今天 ⋅ 0

设计模式--装饰者模式

装饰者模式 定义 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。 通用类图 意图 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比...

gaob2001 ⋅ 今天 ⋅ 0

JavaScript零基础入门——(八)JavaScript的数组

JavaScript零基础入门——(八)JavaScript的数组 欢迎大家回到我们的JavaScript零基础入门,上一节课我们讲了有关JavaScript正则表达式的相关知识点,便于大家更好的对字符串进行处理。这一...

JandenMa ⋅ 今天 ⋅ 0

sbt网络问题解决方案

转自:http://dblab.xmu.edu.cn/blog/maven-network-problem/ cd ~/.sbt/launchers/0.13.9unzip -q ./sbt-launch.jar 修改 vi sbt/sbt.boot.properties 增加一个oschina库地址: [reposit......

狐狸老侠 ⋅ 今天 ⋅ 0

大数据,必须掌握的10项顶级安全技术

我们看到越来越多的数据泄漏事故、勒索软件和其他类型的网络攻击,这使得安全成为一个热门话题。 去年,企业IT面临的威胁仍然处于非常高的水平,每天都会看到媒体报道大量数据泄漏事故和攻击...

p柯西 ⋅ 今天 ⋅ 0

Linux下安装配置Hadoop2.7.6

前提 安装jdk 下载 wget http://mirrors.hust.edu.cn/apache/hadoop/common/hadoop-2.7.6/hadoop-2.7.6.tar.gz 解压 配置 vim /etc/profile # 配置java环境变量 export JAVA_HOME=/opt/jdk1......

晨猫 ⋅ 今天 ⋅ 0

crontab工具介绍

crontab crontab 是一个用于设置周期性被执行的任务工具。 周期性执行的任务列表称为Cron Table crontab(选项)(参数) -e:编辑该用户的计时器设置; -l:列出该用户的计时器设置; -r:删除该...

Linux学习笔记 ⋅ 今天 ⋅ 0

深入Java多线程——Java内存模型深入(2)

5. final域的内存语义 5.1 final域的重排序规则 1.对于final域,编译器和处理器要遵守两个重排序规则: (1)在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用...

江左煤郎 ⋅ 今天 ⋅ 0

面试-正向代理和反向代理

面试-正向代理和反向代理 Nginx 是一个高性能的反向代理服务器,但同时也支持正向代理方式的配置。

秋日芒草 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部