简体   繁体   English

Swift 协议扩展 `var { get }` 覆盖实现的 `let`

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

Implementing property with var and let behaves differently when the implementing struct is assigned to a variable typed as protocol .当将实现结构分配给类型为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.

Is this designed behaviour of Swift?这是 Swift 的设计行为吗?

I think this is a compiler bug.我认为这是一个编译器错误。 If you make a LetReq an optional string, it works as expected:如果您将LetReq可选字符串,它会按预期工作:

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

File a bug with Apple.向 Apple提交错误

I think that behavior is correct.我认为这种行为是正确的。

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

path is String type not String?路径是String类型不是String?

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

req is type of Req . reqReq类型。 So req.path means type is String?所以req.path表示类型是String? and name is path名称是path

Req 's extension has default variable for path variable. Req的扩展具有path变量的默认变量。 so req.path refer that variable not LetReq 's path所以req.path指的是变量不是LetReqpath

It's vague... But I would bet on a bug.这很模糊......但我敢打赌一个错误。

At least for current implementation( swiftc 2.2);至少对于当前的实现( swiftc 2.2);

  1. Swift supports method overloading by only different return types. Swift 仅支持不同返回类型的方法重载。
  2. But only for methods, not properties.但仅适用于方法,不适用于属性。
  3. So, all properties must have different names.因此,所有属性必须具有不同的名称。

This can be proven by this.这可以证明这一点。

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

But anyway, the compiler doesn't seem to check this redeclaration by protocol extension.但无论如何,编译器似乎并没有通过协议扩展来检查这个重新声明。 So, LetReq instance actually provides two properties.所以, LetReq实例实际上提供了两个属性。

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

You can check this with this.你可以用这个来检查这个。

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

I believe this kind of property overloading must be prevented by compiler.我相信编译器必须防止这种属性重载。 For same reason of why they prevented property overloading in struct AA .出于同样的原因,他们阻止了struct AA属性重载。 So, that's a bug in my opinion.所以,在我看来,这是一个错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM