【问题标题】:Swift: Unwrap optional otherwise create new instanceSwift:解包可选否则创建新实例
【发布时间】:2017-11-21 00:47:56
【问题描述】:

我正在使用 let 从字典中解开一个可选项,但发现处理 else 情况很麻烦。

  if let d : Dog = zoo["Barky"]  {
    d.bark()
  } else {
    // Create missing Dog
    let d : Dog = Dog.init()
    zoo["Barky"] = d
    d.bark()
  }

有没有办法让它更简洁/优雅?

  • 如何提取对 bark() 的重复调用
  • 如何避免重复的 let 定义。

【问题讨论】:

标签: swift let


【解决方案1】:

谢谢大家!我在另一个我喜欢的答案中找到了以下 sn-p:

let d = zoo["Barky"] ?? {
  let d = Dog()
  zoo["Barky"] = d
  return d
}()

由于我在很多地方都需要这个成语,所以我也将扩展名添加到Dictionary

extension Dictionary {

    mutating func get_or_set(_ key: Key, defaultValue: () -> Value) -> Value {
        if let value = self[key] {
            return value
        } else {
            let value = defaultValue()
            self[key] = value
            return value
        }
    }
}

let d = zoo.get_or_set("Barky", defaultValue: { Dog() })

然后我发现subscript 运算符也可以重载:

extension Dictionary {    
    subscript(key: Key, defaultFunc defaultFunc: () -> Value) -> Value {
        mutating get { 
            return self[key] ?? { 
                let value = defaultFunc()
                self[key] = value
                return value
            }()
        }
    }
}

var d = zoo["Barky", defaultFunc: { Dog.init() }]

【讨论】:

    【解决方案2】:

    您可以这样使用 ?? 运算符:

    let d = zoo["Barky"] ?? Dog.init()
    zoo["Barky"] = d
    d.bark()
    

    在 Swift 4 中,字典可以有默认值。示例:

    let d = zoo["Barky", default: Dog.init()]
    

    【讨论】:

    • 我自己也是这么想的,可惜他还需要把新的Dog存入zoo字典中。
    • 我想到的唯一快速方法是将对象添加到字典后面的行。不幸的是,Swift 中没有多重赋值。
    • 我不认为启动一个新的字典是一个好主意,因为如果字典再复杂一点,你的答案会更难使用
    【解决方案3】:

    一个更短的替代方案:

    var d: Dog!= zoo["Barky"]
    if d == nil {
        d = Dog()
        zoo["Barky"] = d
    }
    d.bark()
    

    或者(如果您不介意查字典两次):

    if zoo["Barky"] == nil {
        zoo["Barky"] = Dog()
    }
    zoo["Barky"]!.bark()
    

    【讨论】:

      【解决方案4】:

      这个怎么样?

      if zoo["Barky"] == nil {
          zoo["Barky"] = Dog()
      }
      
      zoo["Barky"]?.bark()
      

      【讨论】:

        【解决方案5】:

        你可以用两行代码来实现。 :)

        let d: Dog = zoo["Barky"] ?? Dog()
        zoo["Barky"] = d 
        d.bark()
        

        【讨论】:

        • 这不会将新狗添加到字典中。
        • 您可以轻松添加此行zoo["Barky"] = d ,让我编辑我的答案
        • 现在您不必要地将d 插入到字典中,即使它与字典中已经存在的值相同 - 除了第一次之外,每次都会出现这种情况。
        • tru dat,但如果值相同,它们共享相同的地址,并且由于iOS中的内存管理,这一行将基本上被忽略。如果它不同,它将把它添加到需要的字典中。 :)
        • @HadyNourallah Swift 的 ARC 在这里帮不了你 ;) 确实,这不会导致内存泄漏,但我看不出 Dictonary 更新逻辑将如何优化他的方式围绕这个。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多