当前位置: 首页 > 知识库问答 >
问题:

Swift中的可选值是什么?

廉子民
2023-03-14

为什么要使用可选值?

共有1个答案

富锦
2023-03-14

Swift中的可选项是一种可以保存值或不保存值的类型。可选项是通过在任何类型后附加来编写的:

var name: String? = "Bertie"

选项(以及泛型)是最难理解的快速概念之一。由于它们是如何编写和使用的,所以很容易对它们是什么产生错误的想法。将上面的可选选项与创建普通字符串相比较:

var name: String = "Bertie" // No "?" after String

从语法上看,可选字符串与普通字符串非常相似。这不是。可选字符串不是打开了某些“可选”设置的字符串。这不是一种特殊的弦。字符串和可选字符串是完全不同的类型。

enum Optional<Wrapped> {
    case none
    case some(Wrapped)
}

注意:我会讲很多可选变量,但也可以创建可选常量。我用它们的类型标记所有变量,以便更容易理解正在创建的类型,但您不必在自己的代码中这样做。

若要创建可选,请在要包装的类型后追加。任何类型都可以是可选的,甚至是您自己的自定义类型。类型和之间不能有空格。

var name: String? = "Bob" // Create an optional String that contains "Bob"
var peter: Person? = Person() // An optional "Person" (custom type)

// A class with a String and an optional String property
class Car {
var modelName: String // must exist
var internalName: String? // may or may not exist
}

您可以将可选选项与nil进行比较,以查看它是否具有值:

var name: String? = "Bob"
name = nil // Set name to nil, the absence of a value
if name != nil {
    print("There is a name")
}
if name == nil { // Could also use an "else"
    print("Name has no value")
}
var red: String = "Red"
red = nil // error: nil cannot be assigned to type 'String'

使用一个可选的显示了程序员的意图。与Objective-C相比,在Objective-C中,任何对象都可能为零,Swift需要您明确何时可以缺少一个值,何时可以保证该值存在。

不能使用可选的字符串代替实际的字符串。若要在可选项中使用包装的值,必须将其解包装。打开可选的最简单的方法是在可选名称后面添加。这被称为“强制展开”。它返回可选值内部的值(作为原始类型),但如果可选值为nil,则会导致运行时崩溃。在打开包装之前,您应该确定有一个值。

var name: String? = "Bob"
let unwrappedName: String = name!
print("Unwrapped name: \(unwrappedName)")

name = nil
let nilName: String = name! // Runtime crash. Unexpected nil.

因为在打开包装和使用可选选项之前,您应该始终检查是否为nil,所以这是一种常见的模式:

var mealPreference: String? = "Vegetarian"
if mealPreference != nil {
    let unwrappedMealPreference: String = mealPreference!
    print("Meal: \(unwrappedMealPreference)") // or do something useful
}
var mealPreference: String? = "Vegetarian"
if let unwrappedMealPreference: String = mealPreference {
    print("Meal: \(unwrappedMealPreference)") 
}
var mealPreference: String? = "Vegetarian"
if let mealPreference: String = mealPreference {
    print("Meal: \(mealPreference)") // separate from the other mealPreference
}

下面是一些代码来演示使用了不同的变量:

var mealPreference: String? = "Vegetarian"
if var mealPreference: String = mealPreference {
    print("Meal: \(mealPreference)") // mealPreference is a String, not a String?
    mealPreference = "Beef" // No effect on original
}
// This is the original mealPreference
print("Meal: \(mealPreference)") // Prints "Meal: Optional("Vegetarian")"

可选绑定的工作方式是检查可选值是否等于零。如果不是,它会将可选的解包装到提供的常量中,并执行该块。在Xcode 8.3和更高版本(Swift3.1)中,尝试打印类似这样的可选内容会导致一个无用的警告。使用可选的debugdescription使其静音:

print("\(mealPreference.debugDescription)")

选项有两个用例:

    null
    null
let leatherTrim: CarExtras? = nil
if leatherTrim {
    price = price + 1000
}

在Swift的最新版本中,您必须使用leathertrim!=nil。这是为什么?问题是boolean可以包装在可选的。如果您有以下boolean:

var ambiguous: Boolean? = false

它有两种“false”,一种是没有值,另一种是有值但值是false。Swift讨厌模棱两可,所以现在您必须始终对照nil检查一个可选选项。

您可能想知道可选的boolean有什么意义?与其他选项一样,.none状态可以指示该值尚未未知。网络呼叫的另一端可能有一些东西需要一些时间来轮询。可选布尔值也称为“三值布尔值”

var religiousAffiliation: String? = "Rastafarian"
religiousAffiliation = nil
if religiousAffiliation != nil { ... }
    null

我将介绍允许这些行工作的选项的一些实现细节。

使用创建可选的是语法糖,由Swift编译器启用。如果你想做的很远,你可以创建一个可选的,如下所示:

var name: Optional<String> = Optional("Bob")

这将调用optional的第一个初始值设定项public init(_some:Wrapped),后者根据括号内使用的类型推断出可选项的关联类型。

var serialNumber:String? = Optional.none
serialNumber = Optional.some("1234")
print("\(serialNumber.debugDescription)")
var name: String?
var name: String? = nil

允许选项等于nil是由协议expressiblebynilliteral(以前称为nilliteralconvertible)启用的。可选项是用optional的第二个初始值设定项public init(Nilliteral:())创建的。文档中说,除了选项之外,您不应该对任何东西使用expressiblebynilliteral,因为这会改变代码中nil的含义,但这样做是可能的:

class Clint: ExpressibleByNilLiteral {
    var name: String?
    required init(nilLiteral: ()) {
        name = "The Man with No Name"
    }
}

let clint: Clint = nil // Would normally give an error
print("\(clint.name)")

相同的协议允许您将已经创建的可选设置为nil。虽然不推荐使用,但您可以直接使用nil文字初始值设定项:

var name: Optional<String> = Optional(nilLiteral: ())

选项定义了两个特殊的“==”和“!=”运算符,您可以在optional定义中看到它们。第一个==允许您检查任何可选值是否等于nil。如果关联的类型相同,则设置为.none的两个不同选项将始终相等。当您与nil进行比较时,Swift会在幕后创建一个相同关联类型的可选选项,设置为.none然后使用该选项进行比较。

// How Swift actually compares to nil
var tuxedoRequired: String? = nil
let temp: Optional<String> = Optional.none
if tuxedoRequired == temp { // equivalent to if tuxedoRequired == nil
    print("tuxedoRequired is nil")
}
let numberToFind: Int = 23
let numberFromString: Int? = Int("23") // Optional(23)
if numberToFind == numberFromString {
    print("It's a match!") // Prints "It's a match!"
}

在幕后,Swift在比较之前将非可选包装为可选。它也可以使用文字(if 23==numberFromString{)

我说过有两个==运算符,但实际上有第三个运算符允许您将nil放在比较的左侧

if nil == name { ... }

对可选类型和非可选类型的命名没有Swift约定。人们避免在名称中添加一些东西来显示它是可选的(如“OptionalMiddlename”或“PossiblenumberasString”),而让声明显示它是可选的类型。当您想要命名一些东西来保存可选的值时,这就变得很困难了。名称“middlename”暗示它是一个字符串类型,因此当您从中提取字符串值时,通常会得到类似“actualmiddlename”或“unwrappedmiddlename”或“realmiddlename”的名称。使用可选绑定并重用变量名来解决这一问题。

摘自Swift编程语言的“基础知识”:

Swift还引入了可选类型,用于处理没有值的情况。选项式要么说“有一个值,它等于x”,要么说“根本没有一个值”。选项类似于在Objective-C中使用nil和指针,但它们适用于任何类型,而不仅仅是类。Optionals比Objective-C中的nil指针更安全、更有表现力,是Swift许多最强大功能的核心。

选项是Swift是一种类型安全语言的一个例子。Swift帮助您明确代码可以使用的值类型。如果您的部分代码需要一个字符串,类型安全可以防止您错误地向它传递Int。这使您能够在开发过程中尽早捕获和修复错误。

最后,这里有一首1899年关于选项课的诗:

昨天在楼梯上
我遇到一个不在那里的人
他今天又不在那里
我希望,我希望他能离开
安蒂戈尼什

  • Swift编程指南
  • Swift(中等)中的选项
  • WWDC第402场“SWIFT简介”(14:15左右开始)
  • 更多可选提示和技巧
 类似资料:
  • 问题内容: 从Apple的文档中: 您可以使用和一起使用可能缺少的值。这些值表示为可选值。可选值包含一个值或包含一个指示该值丢失的值。在值的类型后写一个问号(),以将该值标记为可选。 为什么要使用可选值? 问题答案: Swift中的可选类型是可以保存值或不保存值的类型。通过将a附加到任何类型来编写可选内容: 可选(以及泛型)是最难理解的Swift概念之一。由于它们是如何编写和使用的,很容易对它们是

  • 为什么可选在线? 当可选值包含“nil”时,必须将可选类型“Int?”的值解包为“Int”类型的值,并使用“?”合并,以提供默认值,当可选值包含“nil”时使用“!”强制解包以中止执行 所以这修复了它: 如果我将其分解,则会在添加<code>let index</code>时发生更改。。。。 OK -这将返回first的总计数,total不是可选的: 确定-此枚举和总计不是可选的: 错误 - 这会

  • 问题内容: 如何在显示时删除可选值上的文本而不必强制输入。 更新资料 当会话具有值时,其具有值: 问题答案: 您可以使用(null合并运算符)解开它,并提供默认值(如果为nil)

  • 问题内容: 在阅读The Swift Programming Language时 ,我遇到了以下片段: 您可以使用 if 和 let 一起使用可能缺少的值。这些值表示为 optionals 。可选值包含一个值或包含nil来指示该值丢失。在值的类型后写一个问号(?),以将该值标记为可选。 片段1很清楚,但是片段2发生了什么?有人可以分解并解释吗?它只是使用块的替代方法吗?在这种情况下的确切作用是什么

  • 在Swift中处理选项的习惯用法似乎过于冗长,如果您只想在值为零的情况下提供一个默认值: 涉及不必要的代码复制,或者 这需要不是常量。 Scala的选项monad(与Swift的可选选项基本相同)的方法是: 我错过什么了吗?斯威夫特已经有了一个紧凑的方法来实现这一点吗?或者,如果做不到这一点,是否可以在可选的扩展中定义?

  • 在Java8中,可以返回而不是。Java8文档说,可选的是“一个容器对象,它可以包含非空值,也可以不包含非空值。如果存在一个值,isPresent()将返回true,而get()将返回该值。” 在实践中,这为什么有用呢?另外,有没有使用作为首选项的情况?那表演呢?