繁体   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