簡體   English   中英

Swift 協議擴展 `var { get }` 覆蓋實現的 `let`

[英]Swift protocol extension `var { get }` override implementation's `let`

當將實現結構分配給類型為protocol的變量時,使用varlet實現屬性的行為會有所不同。

protocol Req {
  var path: String? { get }
}
extension Req {
  var path: String? { return "Req" }
}

struct LetReq: Req {
  let path = "LetReq"
}
struct VarReq: Req {
  var path: String? { return "VarReq" }
}

var req: Req!

req = VarReq()
req.path // prints "VarReq"

req = LetReq()
req.path // prints "Req" not "LetReq" which seems very awkward.

這是 Swift 的設計行為嗎?

我認為這是一個編譯器錯誤。 如果您將LetReq可選字符串,它會按預期工作:

struct LetReq: Req {
    let path: String? = "LetReq"
}

向 Apple提交錯誤

我認為這種行為是正確的。

struct LetReq: Req {
    let path = "LetReq"
}

路徑是String類型不是String?

var req: Req!
req = LetReq()
req.path

reqReq類型。 所以req.path表示類型是String? 名稱是path

Req的擴展具有path變量的默認變量。 所以req.path指的是變量不是LetReqpath

這很模糊......但我敢打賭一個錯誤。

至少對於當前的實現( swiftc 2.2);

  1. Swift 僅支持不同返回類型的方法重載。
  2. 但僅適用於方法,不適用於屬性。
  3. 因此,所有屬性必須具有不同的名稱。

這可以證明這一點。

struct AA {
    func a() -> String { return "" }
    func a() -> String? { return "" }
    var b: String { return "" }
    var b: String? { return "" } // Error: Invalid redeclaraion of `b`.
}

但無論如何,編譯器似乎並沒有通過協議擴展來檢查這個重新聲明。 所以, LetReq實例實際上提供了兩個屬性。

var path: String { get }
var path: String? { get }

你可以用這個來檢查這個。

print(LetReq().path as String?)    // prints `Optional("Req")`.
print(LetReq().path as String)     // prints `LetReq`.

我相信編譯器必須防止這種屬性重載。 出於同樣的原因,他們阻止了struct AA屬性重載。 所以,在我看來,這是一個錯誤。

暫無
暫無

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

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