关于ios:Swift中的“未包装价值”是什么?

What is an “unwrapped value” in Swift?

我正在按照本教程学习iOS 8/OSX 10.10的Swift,并多次使用术语"展开值",如本段(在"对象和类"下)所示:

When working with optional values, you can write ? before operations
like methods, properties, and subscripting. If the value before the ?
is nil, everything after the ? is ignored and the value of the whole
expression is nil. Otherwise, the optional value is unwrapped, and
everything after the ? acts on the unwrapped value. In both cases, the
value of the whole expression is an optional value.

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

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

这意味着什么?

编辑

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

原始代码

Original code

Cezary的解决方案

Cezary's solution

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

在这两种情况下,结果不应该相同吗?

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


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

例子:

1
2
var canBeNil : Int? = 4
canBeNil = nil

问号表示canBeNil可以是nil

这不起作用:

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

如果变量是可选的,则要从变量中获取值,必须将其展开。这只意味着在结尾加一个感叹号。

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

您的代码应该如下所示:

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

旁白:

还可以声明选项,通过使用感叹号而不是问号自动展开。

例子:

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

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

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

编辑:

您看到的差异正是包装可选值这一事实的症状。上面还有一层。展开版本只显示直线对象,因为它是展开的。

一个快速的操场比较:

playground

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

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

1
2
3
4
5
if let sideLength = optionalSquare?.sideLength {
    println("sideLength is not nil")
} else {
    println("sidelength is nil")
}


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

所以,让我来帮助那些"右脑"(视觉思维)开发者,除了给出正确的答案外,还提供不同的视角。这是一个很好的类比,对我有很大帮助。

生日礼物包装类比

把可选方案想象成像生日礼物一样,用硬的、硬的、彩色的包装。

在打开礼物之前,你不知道包装里有没有什么东西——也许里面什么都没有!如果里面有什么东西,它可能是另一个礼物,也被包裹着,也可能不包含任何东西。你甚至可以打开100个嵌套的礼物,最终发现只有包装。

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

盒子里有什么?类推!

即使你打开了变量,你仍然像布拉德皮特在SE7en的最后一幕(警告:剧透和非常R级的脏话和暴力),因为即使你打开了现在,你也处于以下情况:你现在有nil,或者一个盒子里装着什么(但你不知道是什么)。

你们可能知道什么东西的类型。例如,如果您将变量声明为类型[Int:Any?],那么您就会知道您有一个(可能是空的)字典,其中包含整数下标,可以生成任何旧类型的换行内容。

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

例证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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语言的设计都考虑到了安全性。它是斯威夫特的标志之一,你应该张开双臂欢迎它。它将帮助开发干净、可读的代码,并帮助防止应用程序崩溃。好的。

Swift中的所有期权都用?符号进行划分。通过在声明为可选类型的类型的名称后设置?,您基本上将其转换为不在?之前的类型,而是将其转换为可选类型。好的。

Note: A variable or type Int is not the same as Int?. They are two different types that can not be operated on each other.

Ok.

使用可选好的。

1
2
3
var myString: String?

myString ="foobar"

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

1
print(myString)

运行时,调试控制台将打印Optional("foobar")。"Optional()部分表示该变量在运行时可能有值,也可能没有值,但正好包含字符串"foobar"。除非您执行所谓的"展开"可选值,否则"Optional()"指示将保持不变。好的。

展开一个可选项意味着您现在将该类型强制转换为非可选类型。这将生成一个新类型,并将该可选类型中的值赋给新的非可选类型。通过这种方式,您可以对该变量执行操作,因为编译器保证该变量具有实值。好的。

有条件地展开将检查选项中的值是否为nil。如果不是nil,将有一个新创建的常量变量,该变量将被赋值并展开为非可选常量。在这里,您可以安全地使用if块中的非可选部分。好的。

Note: You can give your conditionally unwrapped constant the same name as the optional variable you are unwrapping.

Ok.

1
2
3
4
if let myString = myString {
    print(myString)
    // will print"foobar"
}

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

1
2
3
4
5
6
7
if let myString = myString {
    print(myString)
    // will print"foobar"
}
else {
    print("No value")
}

强行展开是通过使用被称为!(bang)运算符来完成的。这不太安全,但仍然允许编译代码。但是,无论何时使用bang运算符,都必须确保在强制展开之前变量确实包含实数。好的。

1
2
3
4
5
var myString: String?

myString ="foobar"

print(myString!)

上述代码完全有效。它打印出设定为"foobar"的myString的值。用户会看到控制台上打印了foobar,就这样。但假设从未设置过该值:好的。

1
2
3
var myString: String?

print(myString!)

现在我们有了不同的情况。与Objective-C不同的是,每当试图强制展开某个选项时,如果该选项尚未设置且为nil,则当试图展开该选项以查看应用程序中的内容时,将崩溃。好的。

拆封w/型铸造。正如我们前面所说,当您是unwrapping选项时,实际上您正在强制转换为非可选类型,也可以将非可选类型强制转换为其他类型。例如:好的。

1
var something: Any?

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

Note: The as operator is how you type cast in Swift.

Ok.

1
2
3
4
5
6
7
8
9
10
11
12
// 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)。好的。

如果你曾经试着写作业好的。

1
1 + Optional(1) = 2

你的数学老师可能会给你一个"F"。斯威夫特也一样。但斯威夫特宁愿不编译也不愿给你一个分数。因为在一天结束的时候,这个选项实际上可能是零。好的。

安全第一的孩子。好的。好啊。


"?"表示可选链接表达式"!"手段就是力量值enter image description here