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

时间:2017-01-06 10:23:07

标签: swift xcode optional

城镇结构:

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")
        }
    }
}

Zombie class:

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?,则表示填充是非可选的Int。这两个错误互相矛盾,发生了什么?

4 个答案:

答案 0 :(得分:2)

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

考虑以下示例:

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来查询对bar foo的访问权限如果bar不是.some(...),则会在foo中包含nil的值,否则为nil。即,这样的查询(甚至是作为`bar的非可选属性)将产生一个可选的:

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

反映可以在nil上调用可选链接的事实   value,可选链接调用的结果始终是可选的   值,即使您要查询的属性,方法或下标   返回非可选值。

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

因此,如果您有条件地进入if区块,请给出以下内容:

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

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

你可以这样做,例如组合的可选绑定和布尔条件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构建条件iffoonil或其成员bar不大于0的情况下失败的声明:

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

此处,如果(foo?.bar ?? -1)-1foo会产生nil(随后false会产生-1 > 0),或者如果bar不是Int,则会产生foo(作为非可选具体nil)的值。

我们还可以有条件地使用map method of Optionalfoo不是nil)来测试比较,如果foonil,在从false调用返回时使用nil合并运算符将map作为默认值提供。

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)
}

答案 1 :(得分:0)

表达式返回一个可选的componentDidMount,但您仍在使用非可选语法对其进行测试。您需要使用Int

if let

可选链不会删除可选项。它只是级联它,以便链中的任何零都会导致最后弹出一个零。但结果仍然是可选的。

答案 2 :(得分:0)

因为城镇?。人口仍然是国家?,你无法比较国际?使用Int,除非你从Int获得Int?

所以代码可能是

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

答案 3 :(得分:0)

您必须初始化您构建Town的实例,否则它总是返回nil。所以我看到你的代码,镇?总是回到零。