簡體   English   中英

可選結構的非可選屬性顯示為可選

[英]Non-optional property of optional struct being shown as 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")
        }
    }
}

僵屍類:

class Zombie: Monster {
    var walksWithLimp = true

    final override func terrorizeTown() {

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

        super.terrorizeTown()
    }
}

我在town?.population上遇到編譯器錯誤town?.population說“可選Int的值town?.population包...”。 我還沒有宣布population是可選的,如果我將其更改為town?.population? 它說人口是一個非可選的整數。 這兩個錯誤相互矛盾,這是怎么回事?

可選鏈接,即使在查詢非可選方法和屬性時,也會產生可選的結果

考慮以下示例:

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 ,我們可以使用可選的鏈接查詢訪問barfoo ,這將給我們的價值bar裹着.some(...)的情況下, foo不為nil ,否則為nil 即,這樣的查詢(甚至對非可選屬性,如`bar)將產生可選:

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

為了反映可以在nil值上調用可選鏈接的事實,即使您要查詢的屬性,方法或下標返回非可選值可選鏈接調用的結果也始終是可選值。

在繼續之前,我們還注意到,在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合並運算符來構造條件if語句, if foonil或其成員bar將會失敗。不大於0:

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

在此, (foo?.bar ?? -1)將導致-1如果foonil (其將隨后導致false-1 > 0 ),或導致的值bar (作為非可選混凝土Int )如果foo不為nil

我們還可以使用Optionalmap方法來有條件地(該foo不是nil )進行比較測試,如果foonil ,則在調用map的返回中使用nil合並運算符提供false作為默認值。

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

該表達式返回可選的Int但您仍在使用非可選語法對其進行測試。 您需要使用if let

if let pop = town?.population {
    if pop > 0

等等

可選鏈不會刪除可選性。 它只是簡單地級聯它,以便鏈中的任何零都將在末尾彈出一個零。 但是結果仍然是可選的。

因為town..population仍為Int ?,您無法比較Int? 除非您從Int獲得Int?

所以代碼可能是

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

您必須初始化結構Town的實例,否則它總是返回nil。 所以我看到了您的代碼,Town? 總是返回nil。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM