什么是Swift中的“解包值”?

我正在按照本教程学习Swift for iOS 8 / OSX 10.10,并且使用了几次“ unwrapped value ”这个术语,就像本段落(在Objects和Class下 )一样:

使用可选值时,你可以写? 像方法,属性和下标之类的操作之前。 如果之前的价值? 是零,以后的一切? 被忽略,整个expression式的值是零。 否则, 可选值是unwrapped ,以及后面的一切? 作用于未包装的价值 。 在这两种情况下,整个expression式的值是一个可选值。

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") let sideLength = optionalSquare?.sideLength 

我不明白,并没有运气在网上search。

这是什么意思?


编辑

从Cezary的回答,原始代码的输出和最终解决scheme(在操场上testing)之间有一点点差异:

原始代码

原始代码

Cezary的解决scheme

Cezary的解决方案

超类的属性显示在第二种情况的输出中,而第一种情况下有一个空对象。

两种情况下的结果都不相同吗?

相关问答: 什么是Swift中的可选值?

首先,你必须理解一个可选types是什么。 一个可选types基本上意味着该variables可以 nil

例:

 var canBeNil : Int? = 4 canBeNil = nil 

问号表示canBeNil可以nil的事实。

这不会工作:

 var cantBeNil : Int = 4 cantBeNil = nil // can't do this 

如果它是可选的,要从variables中获取值,则必须将其解包 。 这只是意味着在最后加上感叹号。

 var canBeNil : Int? = 4 println(canBeNil!) 

你的代码应该是这样的:

 let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") let sideLength = optionalSquare!.sideLength 

一个注释:

您还可以声明选项,通过使用感叹号而不是问号来自动解包。

例:

 var canBeNil : Int! = 4 print(canBeNil) // no unwrapping needed 

所以修复你的代码的另一种方法是:

 let optionalSquare: Square! = Square(sideLength: 2.5, name: "optional square") let sideLength = optionalSquare.sideLength 

编辑:

你所看到的差异恰恰是可选值被包装的事实的症状。 它上面还有一层。 展开的版本只是显示了直的对象,因为它被拆开了。

快速的操场比较:

操场

在第一种情况和第二种情况下,对象不会自动解包,所以您会看到两个“图层”( {{...}} ,而在第三种情况下,您只能看到一个图层( {...}因为对象正在自动解包。

第一种情况和第二种情况的区别在于,如果optionalSquare设置为nil ,则后面的两种情况会给您一个运行时错误。 在第一种情况下使用语法,你可以做这样的事情:

 if let sideLength = optionalSquare?.sideLength { println("sideLength is not nil") } else { println("sidelength is nil") } 

现有的正确答案很好,但是我发现,为了让我充分理解这一点,我需要一个很好的比喻,因为这是一个非常抽象和怪异的概念。

所以,除了正确的答案之外,让我帮助那些“右脑”(视觉思维)开发者。 这是一个很好的比喻,帮助了我很多。

生日礼物包装类比

把可选项看作是生硬的,硬的,彩色的包装。

你不知道包裹里有什么东西,直到你打开礼物 – 也许里面什么也没有! 如果里面有什么东西的话,那可能是另外一个礼物了,这个礼物也是包装的,也可能什么没有 。 你甚至可以打开100个嵌套的礼物,最终发现除了包装外什么没有

如果可选的值不是nil ,那么现在你已经显示了一个包含内容的框。 但是,特别是如果这个值没有明确的键入,并且是一个variables而不是一个预定义的常量,那么你可能仍然需要打开这个盒子,然后才能知道什么是盒子里的东西,比如它是什么types的,实际价值是。

盒子里有什么东西?! 比喻

即使在解开variables之后,你仍然像布拉德·皮特在SE7EN的最后一幕 ( 警告 :破坏者和非常R级的粗话和暴力),因为即使你打开礼物之后,你仍然处于以下情况: 你现在nil ,或一个包含的东西 (但你不知道)。

你可能知道某物的types。 例如,如果您将variables声明为types[Int:Any?] ,那么您将知道您有一个带有整数下标的(可能为空的)字典,可以产生任何旧types的封装内容。

这就是为什么在Swift中处理集合types(字典和数组)的原因可能是多毛的。

例如:

 typealias presentType = [Int:Any?] func wrap(i:Int, gift:Any?) -> presentType? { if(i != 0) { let box : presentType = [i:wrap(i-1,gift:gift)] return box } else { let box = [i:gift] return box } } func getGift() -> String? { return "foobar" } let f00 = wrap(10,gift:getGift()) //Now we have to unwrap f00, unwrap its entry, then force cast it into the type we hope it is, and then repeat this in nested fashion until we get to the final value. var b4r = (((((((((((f00![10]! as! [Int:Any?])[9]! as! [Int:Any?])[8]! as! [Int:Any?])[7]! as! [Int:Any?])[6]! as! [Int:Any?])[5]! as! [Int:Any?])[4]! as! [Int:Any?])[3]! as! [Int:Any?])[2]! as! [Int:Any?])[1]! as! [Int:Any?])[0]) //Now we have to DOUBLE UNWRAP the final value (because, remember, getGift returns an optional) AND force cast it to the type we hope it is let asdf : String = b4r!! as! String print(asdf) 

Swift对types安全非常重视。 整个Swift语言的devise都考虑到了安全性。 这是斯威夫特的标志之一,你应该张开双臂迎接。 它将有助于开发干净可读的代码,并帮助防止应用程序崩溃。

Swift中的所有可选项都与? 符号。 通过设置? 在你声明为可选的types的名字之后,你基本上这个types转换成了types, ,而是作为可选的types。


注意:一个variables或types的Int 不是一样的Int? 。 它们是两种不能相互操作的不同types。


使用可选

 var myString: String? myString = "foobar" 

这并不意味着你正在使用一种String 。 这意味着你正在使用一种types的String? (string可选,或可选string)。 事实上,每当你尝试

 print(myString) 

在运行时,debugging控制台将打印Optional("foobar") 。 “ Optional() ”部分表示该variables在运行时可能有或没有值,但恰好当前包含string“foobar”。 这个“ Optional() ”指示将保持,除非你做所谓的“解包”的可选值。

解包可选意味着您现在将该types转换为非可选。 这将生成一个新types,并将该可选中的值分配给新的非可选types。 通过这种方式,您可以对该variables执行操作,因为编译器已经保证它具有可靠的值。


有条件解包将检查可选值是否nil 。 如果不是nil ,则会有一个新创build的常量variables,将被赋值并展开为非可选常量。 从那里你可以安全地使用if的非可选项。

注意:你可以给你的条件解包常量与你正在解包的可选variables名称相同。

 if let myString = myString { print(myString) // will print "foobar" } 

有条件地解包optionals是访问可选值的最简单的方法,因为如果它包含一个零值,那么if let块中的所有内容都不会执行。 当然,就像任何一条语句一样,你可以包含一个else块

 if let myString = myString { print(myString) // will print "foobar" } else { print("No value") } 

强制解包是通过使用所谓的! (“砰”的一声)操作员。 这是不太安全,但仍然允许您的代码进行编译。 但是,无论何时使用bang运算符,您必须确保在强制展开之前variables确实包含一个固定值。

 var myString: String? myString = "foobar" print(myString!) 

上面这个是完全有效的Swift代码。 它打印出被设置为“foobar”的myString的值。 用户会看到在控制台上印刷的foobar ,就是这样。 但是让我们假设价值从未设置:

 var myString: String? print(myString!) 

现在我们手中有不同的情况。 与Objective-C不同的是,每当试图强制打开一个可选项时,可选项还没有被设置,并且nil ,当你试图打开可选项时,看看你的应用程序里面会有什么崩溃。


拆包瓦特/types铸件 。 正如我们前面所说的那样,当你unwrapping可选的选项时,你实际上正在转换成非可选types,你也可以把非可选选项转换为不同的types。 例如:

 var something: Any? 

在我们的代码中的某个地方,variables会被赋值。 也许我们正在使用generics,也许还有一些其他逻辑正在进行,这将导致这种变化。 所以后来在我们的代码中,我们想要使用something但如果它是一个不同的types,仍然可以以不同的方式对待它。 在这种情况下,您将需要使用as关键字来确定:

注意: as运算符是你在Swift中input的types。

 // Conditionally if let thing = something as? Int { print(thing) // 0 } // Optionally let thing = something as? Int print(thing) // Optional(0) // Forcibly let thing = something as! Int print(thing) // 0, if no exception is raised 

注意两者之间的区别as关键字。 像以前一样,当我们强行解开一个可选的时候,我们使用了! 爆炸操作员这样做。 在这里你会做同样的事情,而不是铸造只是一个非可选的,你也把它也作为Int 。 而且它必须能够像Int一样被降级,否则,就像使用bang运算符,当值为nil你的应用程序将会崩溃。

为了在某​​种或者math运算中使用这些variables,它们必须被解开才能这样做。

例如,在Swift中,只有相同types的有效数字数据types可以相互操作。 当你投与一个types的as! 你正在强迫这个variables倒下,就好像你确定它是那种types一样,因此可以安全地操作而不会使应用程序崩溃。 只要variables确实是你正在使用的types,这样就行了,否则你的手上就会一团糟。

尽pipe如此,铸造as! 将允许你的代码编译。 通过铸造一个as? 是一个不同的故事。 其实as? 将您的Int声明为完全不同的数据types。

现在是Optional(0)

如果你曾经试图做你的功课写类似的东西

 1 + Optional(1) = 2 

你的math老师可能会给你一个“F”。 和Swift一样。 除了Swift,宁愿不编译,而不是给你评分。 因为在一天结束的时候可能实际上可能是零

安全第一孩子。

'?' 意思是可选的链式expression

“!”的意思是强制值
在这里输入图像描述