为什么我不能在 Swift 中使用 let in 协议?

我对 Swift 中关于使用 Var关键词{ get set }的协议持怀疑态度。

来自 苹果文档:

如果协议要求属性是可获取和可设置的,则 常量存储的属性不能满足属性要求 或只读计算属性。如果协议只需要 属性是可以得到的,要求可以满足任何种类 属性,并且该属性在以下情况下也是可设置的 这对您自己的代码很有用。

属性要求总是声明为可变属性, 前缀为 var 关键字 通过在类型声明后写入{ get set }来表示,并且 通过写入{ get }来指示 gettable 属性。

我不明白为什么我不能使用 。协议中只有 走开Var不仅仅是 吗?

就像这样:

protocol someProtocol
{
var someProperty: String { get }
}

它不会是公正的:

protocol someProtocol
{
let someProperty: String
}

我错过了什么吗?

26754 次浏览

"A var in a protocol with only get isn't just a let?" No. A let indicates a constant. But that is not the case here. Consider the following:

protocol SomeProtocol {
var someProperty: String { get }
}


class SomeClass : SomeProtocol {


var someProperty: String = ""


func cla () {
someProperty = "asd"
}
}


let someInstance = SomeClass()


print(someInstance.someProperty) // outputs ""
someInstance.cla()
print(someInstance.someProperty) // outputs "asd"

The protocol specifies what the conforming class shows to the outside - some property of type String named someProperty which you can at least get.

If the protocol specifies { get } your class can choose to conform via let someProperty: String = "" but it can similarly choose to conform via the above code. If on the other hand the protocol specifies { get set } you cannot use let in the implementation but have to make it set-able as well.

A protocol simply cannot define that a value has to be constant - neither should it, that is an implementation detail that has to be taken care (or decided about) by the class / struct that implements it.

The difference is between

protocol MyProtocol {
let someProperty: String
}

which makes no sense — a protocol isn't supposed to dictate how someProperty is defined/stored, only that it's available as a property. It could be either a computed or stored property, but that's for the implementer to decide, not the protocol itself.

and

protocol MyProtocol {
var someProperty: String { get }  // abstract interface
}


struct MyStruct: MyProtocol {
let someProperty: String  // concrete implementation: stored property
}


struct OtherStruct: MyProtocol {
let i: Int
var someProperty: String { return "\(i)" }  // concrete implementation: computed property
}

which is perfectly allowed!

I think a protocol can require that a structure has something, but it can't restrict functionality of struct or object. That shouldn't prevent you from doing what you'd probably like to do in code, for example using a var in the protocol and a let for the implementation is acceptable.

protocol MyProtocol {
var trythis: Int { get }
}


struct MyStructure: MyProtocol {
let trythis: Int
}

A property declared with let is considered read-only under the hood. For this reason, a protocol can require that a property be a constant by setting it read-only. This deduction can be verified using some of the Objc runtime functions property_getAttributes.

protocol SomeProtocol {
var someTypeProperty: Int { get }
}


struct Foo: SomeProtocol {
let someTypeProperty: Int
}