1

当将实现结构分配给类型为 的变量时,使用 和 实现属性的行为会var有所不同。letprotocol

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 的设计行为吗?

4

3 回答 3

1

我认为这是一个编译器错误。如果您创建LetReq一个可选字符串,它会按预期工作:

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

向 Apple提交错误

于 2016-05-26T02:20:56.963 回答
0

我认为这种行为是正确的。

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

路径不是String类型String?

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

reqReq. 所以req.path意味着类型是String?并且名称是path

Req的扩展名具有变量的默认path变量。所以req.path参考那个变量 notLetReqpath

于 2016-05-26T03:21:51.063 回答
0

这很模糊......但我敢打赌一个错误。

至少对于当前的实现(swiftc2.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. 所以,在我看来,这是一个错误。

于 2016-05-27T06:00:03.630 回答