打印可选变量


118

我正在尝试这些代码行

class Student {
    var name: String
    var age: Int?

    init(name: String) {
        self.name = name
    }

    func description() -> String {
        return age != nil ? "\(name) is \(age) years old." : "\(name) hides his age."
    }
}

var me = Student(name: "Daniel")
println(me.description())
me.age = 18
println(me.description())

上面的代码产生如下

Daniel hides his age.
Daniel is Optional(18) years old.

我的问题是为什么那里有可选(18),我如何才能删除可选而仅打印

Daniel is 18 years old.

Answers:


190

您必须了解什么是可选的。许多Swift初学者认为var age: Int?,年龄是一个可能具有或没有价值的Int。但这意味着年龄是一个可选参数,它可能包含也可能不包含一个整数。

description()函数内部,您不打印Int,而是打印Optional。如果要打印Int,则必须解开Optional。您可以使用“可选绑定”解开可选:

if let a = age {
 // a is an Int
}

如果确定Optional包含一个对象,则可以使用“强制展开”:

let a = age!

或者在您的示例中,由于您已经在description函数中进行了nil测试,因此您可以将其更改为:

func description() -> String {
    return age != nil ? "\(name) is \(age!) years old." : "\(name) hides his age."
}

我认为如果将示例更改为使用该示例会更好一些if let age = age { return ""} else { return "" }
kubi

13
+1代表:Many Swift beginners think var age: Int? means that age is an Int which may or may not have a value. But it means that age is an Optional which may or may not hold an Int.

18

可选表示Swift无法完全确定值是否与类型相对应:例如,Int?表示Swift不能完全确定数字是否为Int。

要删除它,可以使用三种方法。

1)如果您完全确定类型,可以使用感叹号强制将其拆开,如下所示:

// Here is an optional variable:

var age: Int?

// Here is how you would force unwrap it:

var unwrappedAge = age!

如果您确实强制拆开了一个可选参数并且它等于nil,则可能会遇到以下崩溃错误:

在此处输入图片说明

这不一定安全,因此如果您不确定类型和值,可以使用以下方法避免崩溃:

方法2和3可以防止出现此问题。

2)隐式展开的可选

 if let unwrappedAge = age {

 // continue in here

 }

请注意,展开的类型现在是Int,而不是Int?

3)警卫声明

 guard let unwrappedAge = age else { 
   // continue in here
 }

从这里开始,您可以继续使用unwrapped变量。如果您确定变量的类型,请确保仅强制展开(带有!)。

祝您项目顺利!


1
使用返回年龄!= nil?“(名字)已经(年龄!)岁了。” :“(名称)隐藏了他的年龄。”
leedream,2015年

1
我遇到的一个问题使我免于头痛。感激不尽。
Bruno Recillas

8

出于测试/调试的目的,我经常希望将可选内容作为字符串输出,而不必始终测试nil值,因此我创建了一个自定义运算符。

在阅读了另一个问题的答案后,我甚至进一步改善了情况。

fileprivate protocol _Optional {
    func unwrappedString() -> String
}

extension Optional: _Optional {
    fileprivate func unwrappedString() -> String {
        switch self {
        case .some(let wrapped as _Optional): return wrapped.unwrappedString()
        case .some(let wrapped): return String(describing: wrapped)
        case .none: return String(describing: self)
        }
    }
}

postfix operator ~? { }
public postfix func ~? <X> (x: X?) -> String {
    return x.unwrappedString
}

显然,可以根据自己的喜好调整运算符(及其属性),也可以使其成为函数。无论如何,这使您可以编写如下的简单代码:

var d: Double? = 12.34
print(d)     // Optional(12.34)
print(d~?)   // 12.34
d = nil
print(d~?)   // nil

集成了其他人的协议思想后,它甚至可以与嵌套的可选对象一起使用,而嵌套可选对象通常在使用可选链接时发生。例如:

let i: Int??? = 5
print(i)              // Optional(Optional(Optional(5)))
print("i: \(i~?)")    // i: 5

1
从Swift 3开始,您还可以使用Swift标准库函数debugPrint(_:separator:terminator :)。但是,这会将字符串用双引号引起来。
psmythirl

@psmythirl:很高兴知道!但是有时您可能只想在String其他地方传递或嵌入一个可选参数(例如,日志/错误消息)。
杰里米(Jeremy)2016年

print(d as Any)
DawnSong

7

更新资料

只需使用me.age ?? "Unknown age!"。它适用于3.0.2。

旧答案

如果没有强制展开(如果没有,则没有马赫信号/崩溃),另一种不错的方法是:

(result["ip"] ?? "unavailable").description

result["ip"] ?? "unavailable" 应该也有工作,但至少在2.2中没有

当然,用适合您的内容替换“不可用”:“无”,“找不到”等


4

要解开可选内容,请使用age!代替age。目前,您正在打印可能为的可选值nil。那就是为什么它包裹着Optional


4

在某些情况下Optional可能很快nil。如果您100%确定a variable将始终具有某些值,并且不会返回带有变量nil的add !来强制展开它。

在其他情况下,如果您不太确定值,则添加一个if let块或guard确保该值存在,否则可能导致崩溃。

对于if let块:

if let abc = any_variable {
 // do anything you want with 'abc' variable no need to force unwrap now.
}

对于guard语句:

guard 是一个条件结构,如果不满足条件则返回控制。

我更喜欢在许多情况下使用guardover if let块,因为它允许我们在function不存在特定值的情况下返回。就像有一个变量存在整数的函数一样,我们可以在guard语句中检查它,并且不返回它。即

guard let abc = any_variable else { return }

如果变量存在,我们可以在保护范围之外的函数中使用“ abc”。


3

age是可选类型:Optional<Int>因此,如果将其与nil进行比较,则每次有值或没有值时,它都会返回false。您需要打开可选组件以获取值。

在您的示例中,您不知道它是否包含任何值,因此您可以改用以下值:

if let myAge = age {
    // there is a value and it's currently undraped and is stored in a constant
}
else {
   // no value
}

3

我这样做是为了从另一个视图控制器打印字符串(属性)的值。

ViewController.swift

var testString:NSString = "I am iOS Developer"

SecondViewController.swift

var obj:ViewController? = ViewController(nibName: "ViewController", bundle: nil)
print("The Value of String is \(obj!.testString)")

结果:

The Value of String is I am iOS Developer

2
您不应该强行打开可选包装
E-Riddie

3

查看以下guard语句:

for student in class {
    guard let age = student.age else { 
        continue 
     }
    // do something with age
}

3

具有默认值时:

print("\(name) is \(age ?? 0) years old")

或名称为可选项时:

print("\(name ?? "unknown") is \(age) years old")


1

我在tableview单元格中得到了Optional(“ String”)。

第一个答案很好。并帮助我弄清楚了。这是我所做的,以帮助像我这样的新秀。

由于我是在自定义对象中创建一个数组,因此我知道它始终将项目放在第一个位置,因此我可以强制将其包装到另一个变量中。然后使用该变量进行打印,或者在我的情况下,将其设置为tableview单元格文本。

let description = workout.listOfStrings.first!
cell.textLabel?.text = description

现在看来如此简单,但花了我一段时间才弄清楚。


-1

这不是对这个问题的确切答案,而是造成这种问题的原因之一。就我而言,我无法使用“ if let”和“ guard let”从字符串中删除Optional。

因此,使用AnyObject而不是Any可以迅速从字符串中删除可选。

请参考链接以获取答案。

https://stackoverflow.com/a/51356716/8334818

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.