首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >什么是Swift中的“解包值”?

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

Stack Overflow用户
提问于 2014-06-04 18:02:41
回答 5查看 83K关注 0票数 159

我正在学习适用于iOS 8/OSX10.10的Swift,遵循this tutorial,术语“解包值”被多次使用,就像下面这段(在对象和类下面):

当使用可选值时,您可以写?在方法、属性和下标等操作之前。如果前面的值?是不是零,后面的都是?被忽略,并且整个表达式的值为nil。否则,取消包装可选值,以及?之后的所有内容。对未包装的值执行操作。在这两种情况下,整个表达式的值都是可选值。

代码语言:javascript
复制
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare?.sideLength

我不明白,我在网上搜索,但没有运气。

这意味着什么?

编辑

根据Cezary的回答,原始代码和最终解决方案(在操场上测试)的输出之间存在细微的差异:

原始代码

塞扎里解决方案

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

两种情况下的结果不是应该是相同的吗?

相关问答:

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2014-06-04 18:05:41

首先,您必须了解什么是可选类型。可选类型基本上意味着变量可以是nil

示例:

代码语言:javascript
复制
var canBeNil : Int? = 4
canBeNil = nil

问号表示canBeNil可以为nil

这是行不通的:

代码语言:javascript
复制
var cantBeNil : Int = 4
cantBeNil = nil // can't do this

要从变量中获取值(如果它是可选的),您必须将其解包为。这只意味着在末尾加一个感叹号。

代码语言:javascript
复制
var canBeNil : Int? = 4
println(canBeNil!)

您的代码应如下所示:

代码语言:javascript
复制
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare!.sideLength

附注:

您还可以通过使用感叹号而不是问号来声明要自动展开的可选参数。

示例:

代码语言:javascript
复制
var canBeNil : Int! = 4
print(canBeNil) // no unwrapping needed

因此,修复代码的另一种方法是:

代码语言:javascript
复制
let optionalSquare: Square! = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare.sideLength

编辑:

您所看到的不同之处正是可选值是包装的这一事实的症状。在它的上面还有另一层。未包装的版本只显示了直接的对象,因为它是未包装的。

快速比较一下游乐场:

在第一种和第二种情况下,对象不会自动展开,因此您会看到两个“层”({{...}}),而在第三种情况下,您只会看到一层({...}),因为对象会自动展开。

第一种情况和后两种情况的不同之处在于,如果optionalSquare设置为nil,后两种情况将产生运行时错误。使用第一种情况中的语法,您可以执行如下操作:

代码语言:javascript
复制
if let sideLength = optionalSquare?.sideLength {
    println("sideLength is not nil")
} else {
    println("sidelength is nil")
}
票数 295
EN

Stack Overflow用户

发布于 2016-03-14 06:47:11

现有的正确答案很好,但我发现为了完全理解这一点,我需要一个很好的类比,因为这是一个非常抽象和奇怪的概念。

因此,让我通过给出正确答案之外的不同观点来帮助那些“右脑”(视觉思维)开发人员。这里有一个很好的类比,它对我帮助很大。

生日礼物包装类比

把可选的东西想象成像生日礼物一样,包装得很硬、很硬、很彩色。

直到你打开礼物,你才知道包装里有没有东西--也许里面什么都没有!如果里面有什么东西,它可能是另一件礼物,也是包装好的,也可能什么也没有。你甚至可能拆开100件嵌套的礼物,最终发现除了包装什么都没有。

如果optional的值不是nil,那么现在您已经显示了一个包含某些内容的框。但是,特别是如果值不是显式类型的,并且是一个变量而不是预定义的常量,那么您可能仍然需要打开框,然后才能知道框中有什么具体内容,比如它是什么类型,或者实际值是什么。

盒子里有什么?!

即使在您解开变量之后,您仍然像last scene in SE7EN中的Brad Pitt (警告:剧透和非常R级的粗话和暴力),因为即使在您已经解开了礼物之后,您仍然处于以下情况:您现在有了或者一个包含__(但您不知道是什么).**的盒子

你可能知道某些东西的类型。例如,如果您将变量声明为[Int:Any?]类型,那么您就知道您有一个(可能为空的)带有整数下标的字典,它会生成任何旧类型的包装内容。

这就是为什么在Swift中处理集合类型(字典和数组)会有些麻烦。

举个例子:

代码语言:javascript
复制
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)
票数 17
EN

Stack Overflow用户

发布于 2017-04-22 04:50:20

Swift非常重视类型安全。整个Swift语言在设计时都考虑到了安全性。这是Swift的标志之一,您应该张开双臂欢迎它。它将有助于开发干净、可读的代码,并帮助防止应用程序崩溃。

Swift中的所有可选项都以?符号为界。通过在声明为可选的类型名称之后设置?,实质上不是将其转换为?之前的类型,而是将其转换为可选类型。

注意:变量或类型Int is

as Int?。它们是两种不同的类型,不能相互操作。

使用可选的

代码语言:javascript
复制
var myString: String?

myString = "foobar"

这并不意味着你正在使用的是一种类型的String。这意味着您正在使用一种类型的字符串( String? Optional或Optional String)。事实上,每当你尝试

代码语言:javascript
复制
print(myString)

在运行时,调试控制台将打印Optional("foobar")。"Optional()“部分表明此变量在运行时可能有值,也可能没有值,但恰好当前包含字符串"foobar”。此"Optional()“指示将保持不变,除非您执行所谓的”解包“可选值。

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

有条件地展开将检查optional中的值是否为nil。如果它不是nil,将有一个新创建的常量变量,该常量变量将被赋值并展开为非可选常量。然后,您就可以在if块中安全地使用非可选的了。

注意:您可以为有条件取消包装的常量提供与要取消包装的可选变量相同的名称。

代码语言:javascript
复制
if let myString = myString {
    print(myString)
    // will print "foobar"
}

有条件地展开optionals是访问optional的值的最干净的方式,因为如果它包含nil值,那么if let块中的所有内容都将不会执行。当然,与任何if语句一样,您可以包含一个else块

代码语言:javascript
复制
if let myString = myString {
    print(myString)
    // will print "foobar"
}
else {
    print("No value")
}

强制解包是通过使用所谓的! (“”)运算符来完成的。这不太安全,但仍然允许您的代码编译。然而,无论何时使用bang运算符,在强制展开之前,您必须1000%确定您的变量确实包含实值。

代码语言:javascript
复制
var myString: String?

myString = "foobar"

print(myString!)

上面的代码是完全有效的Swift代码。它会打印出设置为"foobar“的myString的值。用户将在控制台中看到打印的foobar,仅此而已。但是让我们假设这个值从未被设置过:

代码语言:javascript
复制
var myString: String?

print(myString!) 

现在我们有了一个不同的情况。与Objective-C不同的是,每当试图强行解包optional,而optional尚未设置且为nil时,当您试图解包optional以查看应用程序内部的内容时,应用程序将崩溃。

使用类型转换进行解包。正如我们前面所说的,当您unwrapping可选类型时,您实际上是在将其强制转换为非可选类型,您也可以将非可选类型强制转换为其他类型。例如:

代码语言:javascript
复制
var something: Any?

在我们的代码中的某个地方,变量something将被设置为某个值。也许我们正在使用泛型,或者可能有一些其他的逻辑正在进行,这将导致这一点发生变化。因此,在稍后的代码中,我们希望使用something,但如果它是不同的类型,则仍然能够以不同的方式处理它。在这种情况下,您需要使用as关键字来确定这一点:

注意:as运算符是您在Swift中键入cast的方式。

代码语言:javascript
复制
// 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关键字之间的区别。就像以前一样,当我们强行打开一个可选的时,我们使用了! bang操作符。在这里,您将执行相同的操作,但不是将其强制转换为非可选类型,而是将其强制转换为Int。并且它必须能够向下转换为Int,否则,就像当值为nil时使用bang操作符一样,您的应用程序将崩溃。

为了在某种类型或数学运算中使用这些变量,必须将它们展开。

例如,在Swift中,只有相同类型的有效数字数据类型才能相互操作。当你使用as!转换一个类型时,你是在强制该变量的向下转换,就好像你是某个,它就是那个类型,因此可以安全地操作而不会使你的应用程序崩溃。这是可以的,只要变量确实是您要将其强制转换为的类型,否则会弄得一团糟。

尽管如此,使用as!进行类型转换将允许编译您的代码。通过使用as?进行转换则是另一回事。实际上,as?将您的Int声明为完全不同的数据类型。

现在是 Optional(0)

如果你曾经尝试做作业,写一些像这样的东西

代码语言:javascript
复制
1 + Optional(1) = 2

你的数学老师可能会给你一个"F“。斯威夫特也是如此。除了Swift宁愿根本不编译也不给你评分。,因为在一天结束的时候,可选项实际上可能是nil

安全第一的孩子。

票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24034483

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档