[英]Class With Non-Optional Property Conforming To Protocol With Optional Property
[英]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
,我們可以使用可選的鏈接查詢訪問bar
中foo
,這將給我們的價值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
foo
為nil
或其成員bar
將會失敗。不大於0:
if (foo?.bar ?? -1) > 0 {
print("'foo' is not nil and its 'bar' member is larger than 0")
}
在此, (foo?.bar ?? -1)
將導致-1
如果foo
是nil
(其將隨后導致false
為-1 > 0
),或導致的值bar
(作為非可選混凝土Int
)如果foo
不為nil
。
我們還可以使用Optional
的map
方法來有條件地(該foo
不是nil
)進行比較測試,如果foo
為nil
,則在調用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.