繁体   English   中英

了解if let语句的逻辑-初始化之前使用的变量

[英]Understanding the logic of an if let statement - variable used before being initialized

因此,我正在关注udemy的教程,并准备了这段代码。

   let itemsObject = UserDefaults.standard.object(forKey: "items")
    var items:[String]

    if let tempItems = itemsObject as? [String]
    {
        //
        items = tempItems
        items.append(textfield.text!)
    }

我了解itemsObject和items数组,但我想知道为什么我不能完全绕过tempItems常量,如...

var items:[String]
if items = itemsObject as? [String]
{
items.append(textfield.text!)
}

我不明白让tempItems常量的目的。

let itemsObject = UserDefaults.standard.object(forKey: "items")

itemsObject现在的类型为Any? 因此,我们需要做两件事:投射并检查是否为零

if let tempItems = itemsObject as? [String]

是以下操作的快捷方式:

let tempItems1 = itemsObject as? [String] // cast to [String]?
if tempItems1 != nil {
    let tempItems2 = tempItems1! // we know its not nil, so force unwrap it to [String]
    ...
}

暗示:

[String]? 是可以为nil的字符串数组

[String]是不能为nil的字符串数组

可选绑定是值绑定模式匹配,这不等于分配

考虑下面的简化示例:

let foo: Any = 1

if let bar = foo as? Int { /* ... */ }

那么我们在最后一行做什么呢? 我们尝试将Any实例( foo )有条件地转换为Int类型。 这样的条件类型转换( as? )的结果是Optional

foo as? Int // type: Optional<Int>

接下来,我们尝试可能成功的转换绑定Int类型的不变实例( bar属性)。 有关详细信息,请参见语言指南中的可选绑定

现在,我们执行可选绑定的方法只是用于值绑定模式匹配的语法糖,在(给定成功的模式匹配)尝试将enum案例的关联值绑定到属性的情况下。 可选绑定的语法糖可用于极端通用的Optional<Wrapped>枚举类型,而对于其他enum类型,我们需要使用通用值绑定模式语法

if case let .anEnumCase(bindAssociatedValueToMe) = someEnumInstance { /* ... */ }

// alternatively
if case .anEnumCase(let bindAssociatedValueToMe) = someEnumInstance { /* ... */ }

即,以下两个(三个)是等效的

// make use of syntactic sugar available for `Optional` enum
if let bar = foo as? Int { /* .. */ }

// or use the explicit value-binding pattern available to any
// enum with a case that holds and associated value
if case .some(let bar) = foo as? Int { /* .. */ }

// (for the latter: alternatively)
if case let .some(bar) = foo as? Int { /* .. */ }

并且,为了使问题更加混乱,我们还为特殊枚举Optional<Wrapped> (特别是.some(let bindWrappedToThis)情况)提供了另一种特殊的语法糖,因此以下内容也等同于两者以上:

// using the sugar '_?' instead of '.some(_)', here replacing
// '... let .some(bar)' with '... let bar?'
if case let bar? = foo as? Int { /* .. */ }

理解以上内容的关键是要了解以下内容:

  1. 尝试的类型转换, as? ,将导致Optional<Wrapped>实例,其中Wrapped类型是类型转换的目标类型。 即, someInstance as? SomeType someInstance as? SomeType将导致Optional<SomeType>的实例,该实例可能为nil.none ),或者可能包装了SomeType的具体实例( .some(someInstanceOfSomeType) )。

  2. 在Swift中,类型Optional<Wrapped>的类型是,当排除所有特殊的整洁度/糖时,是一个枚举,

  3. 最后,值绑定模式匹配与赋值不同。

1)通过详尽的说明是不言自明的。 为了理解2)和3),我们可以研究以下简单示例,显示一个自定义的“可选”类enum并带有一个持有通用关联值的用case ,对于一个给定的enum实例,我们尝试有条件地绑定到物业:

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

// instantiate with a case with an associated value
let foo = MyOptional.some(1) // MyOptional<Int>.some(1)

// use value-binding pattern matching to conditionally
// access the associated value of the 'some(...)' case,
// given that 'foo' is '.some' (and not '.none')
if case .some(let bar) = foo { /* .. */ }

请注意上面最后一行中的值绑定,并与上面的上一代码片段中的非推荐的可选绑定进行比较。


最后,请注意,除了可选绑定之外,您还具有其他手段来访问(可选)(可能存在的)包装值并对其执行操作。 例如,使用Optionalmap(_:)方法,为清楚起见,我们可以将您的示例代码(以及使items不可变)简化为以下示例:

let items = (UserDefaults.standard.object(forKey: "items") as? [String])
    .map { $0 + [textfield.text!] } ?? []

在单个表达式中使用以下内容:

  • UserDefaults值的条件类型转换为类型[String]
  • 如果成功进行类型转换,请附加textField.text! 到具体的[String]值并分配给items
  • 如果类型转换失败,请使用nil合并运算符?? 提供并清空数组[]作为items的默认值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM