【问题标题】:Printing optional variable打印可选变量
【发布时间】:2014-11-08 21:24:29
【问题描述】:

我正在尝试使用这些代码行

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.

我的问题是为什么那里有 Optional (18),我怎样才能删除 optional 而只是打印

Daniel is 18 years old.

【问题讨论】:

    标签: swift


    【解决方案1】:

    您必须了解 Optional 的真正含义。许多 Swift 初学者认为 var age: Int? 意味着 age 是一个 Int ,它可能有值,也可能没有值。但这意味着年龄是一个可选的,它可能持有也可能不持有 Int。

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

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

    如果你确定 Optional 持有一个对象,你可以使用“强制展开”:

    let a = age!
    

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

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

    【讨论】:

    • 我认为如果你把这个例子改成使用if let age = age { return ""} else { return "" }
    • +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.
    【解决方案2】:

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

    1. 如果你完全确定类型,你可以使用感叹号强制解包,像这样:

      // 这里是一个可选变量:

      var age: Int?

      // 下面是强制解包的方法:

      var unwrappedAge = 年龄!

    如果你强制解包一个可选项并且它等于 nil,你可能会遇到这个崩溃错误:

    这不一定安全,所以如果你不确定类型和值,这里有一个方法可以防止崩溃:

    方法二和三可以防止这个问题。

    1. 隐式展开的可选

      如果让 unwrappedAge = 年龄 {

      //在这里继续

      }

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

    1. 守卫声明

      guard let unwrappedAge = age else { // 在这里继续 }

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

    祝你的项目好运!

    【讨论】:

    • 使用返回年龄 != nil ? “(名字)是(年龄!)岁。” :“(姓名)隐藏了他的年龄。”
    • 解决了我遇到的问题。感激不尽。
    • Swift 百分百确定该值是可选的。 optional 绝对不是 Int,因此 Swift 百分百确定该值不是 Int。可选的 可以包含 Int 或不包含值。
    【解决方案3】:

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

    阅读this answer in another question后,我进一步改进了。

    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
    

    【讨论】:

    • 从 Swift 3 开始,您还可以使用 Swift 标准库函数 debugPrint(_:separator:terminator:)。然而,这将在双引号中打印字符串。
    • @psmythirl:很高兴知道!但是,有时您可能只想简单地将可选参数作为 String 传递或嵌入到其他地方(例如日志/错误消息)。
    • 打印(d as Any)
    【解决方案4】:

    更新

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

    旧答案

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

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

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

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

    【讨论】:

      【解决方案5】:

      要打开可选的包装,请使用age! 而不是age。当前,您正在打印可能是nil 的可选值。这就是为什么它用Optional 包裹起来。

      【讨论】:

        【解决方案6】:

        在某些情况下,Optional 可以是 nil。如果您 100% 确定 variable 将始终具有某些值并且不会返回 nil,则添加 ! 和变量以强制解包它。

        在其他情况下,如果您不太确定值,请添加 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 是一个条件结构,如果条件不满足则返回控制。

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

        guard let abc = any_variable else { return }
        

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

        【讨论】:

          【解决方案7】:

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

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

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

          【讨论】:

            【解决方案8】:

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

            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
            

            【讨论】:

            • 你不应该强制打开一个可选的
            【解决方案9】:

            查看guard 声明:

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

            【讨论】:

              【解决方案10】:

              当有默认值时:

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

              或者当名字是可选的:

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

              【讨论】:

                【解决方案11】:

                我在我的表格视图单元格中获得了 Optional("String")。

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

                因为我在我的自定义对象中创建了一个数组,我知道它总是在第一个位置有项目,所以我可以强制将它解包到另一个变量中。然后使用该变量打印,或者在我的情况下,设置为 tableview 单元格文本。

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

                现在看起来很简单,但我花了一段时间才弄明白。

                【讨论】:

                  【解决方案12】:

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

                  所以使用 AnyObject 而不是 Any 在 swift 中从字符串中删除可选项。

                  答案请参考链接。

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

                  【讨论】:

                    【解决方案13】:

                    如果您只是想摆脱Optional(xxx) 之类的字符串,而在某处打印某些值(例如日志)时获取xxxnil,则可以在代码中添加以下扩展名:

                    extension Optional {
                        var orNil: String {
                            if self == nil {
                                return "nil"
                            }
                            return "\(self!)"
                        }
                    }
                    

                    然后是下面的代码:

                    var x: Int?
                    
                    print("x is \(x.orNil)")
                    
                    x = 10
                    
                    print("x is \(x.orNil)")
                    

                    会给你:

                    x is nil
                    x is 10
                    

                    PS。属性命名(orNil)显然不是最好的,但我想不出更清晰的东西。

                    【讨论】:

                      【解决方案14】:

                      使用以下代码,您可以打印它或打印一些默认值。这就是我认为 XCode 通常推荐的内容

                      var someString: String?
                      
                      print("Some string is \(someString ?? String("Some default"))")
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2014-03-15
                        • 1970-01-01
                        • 2016-09-15
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2021-01-28
                        相关资源
                        最近更新 更多