swift - 可选结构的非可选属性显示为可选

标签 swift xcode option-type

城镇结构:

struct Town {
    var population: Int = 5_422
    var numberOfStoplights: Int = 4

    func printDescription() {
        print("The town has \(population) people and \(numberOfStoplights) stoplights")
    }

    mutating func changePopulation(by amount: Int) {
        population += amount
    }
}

怪物类:

class Monster {
    var town: Town?
    var name = "Monster"

    func terrorizeTown() {
        if town != nil {
            print("\(name) is terrorizing a town")
        } else {
            print("\(name) hasn't found a town to terrorize yet")
        }
    }
}

僵尸类:

class Zombie: Monster {
    var walksWithLimp = true

    final override func terrorizeTown() {

        if town?.population > 0 {
            town?.changePopulation(by: -10)
        }

        super.terrorizeTown()
    }
}

我在 town?.population 上遇到编译器错误,提示“可选 Int 的值未展开...”。我还没有将 population 声明为可选,如果我将其更改为 town?.population?,它表示 population 是一个非可选 Int。这两个错误相互矛盾,这是怎么回事?

最佳答案

可选链接,即使在查询非可选方法和属性时,也会产生一个可选的结果

考虑以下示例:

struct Foo {
    let bar: Int // not: not an optional
    init(_ bar: Int) { self.bar = bar }
}

let foo: Foo? = Foo(42) // 'foo' is an optional

如果我们不是特别对 foo 感兴趣,而是特别对它的成员 bar 感兴趣,我们可以使用 optional chaining查询对 foobar 的访问,这将为我们提供包含在 .some(...)< 中的 bar 的值 如果 foo 不是 nil,否则为 nil。也就是说,这样的查询(甚至是非可选属性如 `bar)将产生一个可选的:

let optBar = foo?.bar // this is now an optional (Optional<Int>)

To reflect the fact that optional chaining can be called on a nil value, the result of an optional chaining call is always an optional value, even if the property, method, or subscript you are querying returns a nonoptional value.

在我们继续之前,我们还注意到,在 Swift 3 中,我们可能不再通过 Comparable 运算符比较可选操作数,如以下已接受和实现的 Swift 演进提案中所述:

因此,如果您希望有条件地进入 if block ,给出以下条件:

  • foo 不是nil,并且
  • 如果是,bar 大于 0

然后您首先需要以某种方式实现(可能存在的)bar 的具体值,然后再将其与 0 进行比较。

你可以这样做,例如组合的可选绑定(bind)和 bool 条件 if 语句:

if let nonOptionalBar = foo?.bar, nonOptionalBar > 0 {
    print("'foo' is not nil and its 'bar' member is larger than 0")
} // prints "'foo' is not nil and its 'bar' member is larger than 0"

如果您不打算使用值 bar,但是(并且只想减少它的数量),您可以使用 nil coalescing operator构造一个条件 if 语句,如果 foonil 或其成员 bar 不大于0:

if (foo?.bar ?? -1) > 0 {
    print("'foo' is not nil and its 'bar' member is larger than 0")
}

此处,如果 foonil(foo?.bar ?? -1) 将导致 -1 code>(随后将导致 -1 > 0false),或导致 bar 的值(作为非可选具体的 Int),以防 foo 不是 nil

我们还可以利用 map method of Optional有条件地(foo 不是 nil)测试比较,如果 foonil,则提供 false 作为默认值,在调用 map 时使用 nil 合并运算符。

if foo.map({ $0.bar > 0 }) ?? false {
    print("'foo' is not nil and its 'bar' member is larger than 0")
}

适用于您的示例的三个备选方案:

if let population = town?.population, population > 0 {
    town?.changePopulation(by: -10)
}

if (town?.population ?? -1) > 0 {
    town?.changePopulation(by: -10)
}

if town.map({ $0.population > 0 }) ?? false {
    town?.changePopulation(by: -10)
}

关于swift - 可选结构的非可选属性显示为可选,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41503579/

相关文章:

ios - UILabel下的UIVIew动画

ios - 将 WebView 与 Firebase 数据库结合使用

ios - 从一个全局位置收听 NSNotification

iphone - 阻止用户在我的应用中使用表情符号微笑

ios - UIScrollView 在滚动时暂停 NSTimer

kotlin - 为什么 Kotlin 中的选项需要显式初始化?

json - Swift - 解析多个可选 Json 答案

swift - swift 中是否可以在与多个键关联的字典中拥有相同的集合实例?

ios - 更改 UICollectionView 的默认可访问性行为

ios - 如何最好地管理 Swift 中的可选数组?