ios Swift 协议只能设置吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30573872/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Swift Protocol get only settable?
提问by Artur Pajonk
why can I do this without any error:
为什么我可以在没有任何错误的情况下执行此操作:
var testDto = ModelDto(modelId: 1)
testDto.objectId = 2
while I define this:
虽然我定义了这个:
protocol DataTransferObject {
var objectType: DtoType { get }
var parentObjectId: Int { get set }
var objectId: Int { get }
var objectName: String { get set }
}
struct ModelDto: DataTransferObject {
var objectType: DtoType
var parentObjectId: Int
var objectId: Int
var objectName: String
init(modelId: Int) {
self.objectType = DtoType.Model
self.objectId = modelId
self.parentObjectId = -1
self.objectName = String()
}
}
If the definition in my protocol is mostly ignored (getter, setter definition), why should I use them anyway?
如果我的协议中的定义大多被忽略(getter、setter 定义),我为什么还要使用它们?
采纳答案by Ankit Goel
As per the official documentation:
根据官方文档:
The getter and setter requirements can be satisfied by a conforming type in a variety of ways. If a property declaration includes both the get and set keywords, a conforming type can implement it with a stored variable property or a computed property that is both readable and writeable (that is, one that implements both a getter and a setter). However, that property declaration can't be implemented as a constant property or a read-only computed property. If a property declaration includes only the get keyword, it can be implemented as any kind of property.
getter 和 setter 的要求可以通过多种方式通过符合性的类型来满足。如果属性声明同时包含 get 和 set 关键字,则符合类型可以使用存储变量属性或既可读又可写的计算属性(即同时实现 getter 和 setter 的属性)来实现它。但是,该属性声明不能实现为常量属性或只读计算属性。如果属性声明仅包含 get 关键字,则可以将其实现为任何类型的属性。
回答by Imanou Petit
Apple states in the "Swift Programming Language (Swift 3)":
Apple 在“Swift 编程语言 (Swift 3)”中声明:
If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for the property to be also settable if this is useful for your own code.
如果协议只要求一个属性是可获取的,那么任何类型的属性都可以满足该要求,并且如果这对您自己的代码有用,那么该属性也可以设置是有效的。
For this reason, the five following Playground code snippets are all valid:
因此,以下五个 Playground 代码片段都是有效的:
Example #1: constant property
示例 #1:常量属性
protocol FullyNamed {
var fullName: String { get }
}
struct Duck: FullyNamed {
let fullName: String
}
let scrooge = Duck(fullName: "Scrooge McDuck")
print(scrooge.fullName) // returns "Scrooge McDuck"
Example #2: variable property
示例#2:变量属性
protocol FullyNamed {
var fullName: String { get }
}
struct Duck: FullyNamed {
var fullName: String
}
var scrooge = Duck(fullName: "Scrooge McDuck")
print(scrooge.fullName) // returns "Scrooge McDuck"
scrooge.fullName = "Scrooge H. McDuck"
print(scrooge.fullName) // returns "Scrooge H. McDuck"
Example #3: computed property (get only)
示例 #3:计算属性(仅限获取)
protocol FullyNamed {
var fullName: String { get }
}
struct Duck: FullyNamed {
private var name: String
var fullName: String {
return name
}
}
let scrooge = Duck(name: "Scrooge McDuck")
print(scrooge.fullName) // returns "Scrooge McDuck"
Example #4: computed property (get and set)
示例 #4:计算属性(获取和设置)
protocol FullyNamed {
var fullName: String { get }
}
struct Duck: FullyNamed {
private var name: String
var fullName: String {
get {
return name
}
set {
name = newValue
}
}
}
var scrooge = Duck(name: "Scrooge McDuck")
print(scrooge.fullName) // returns "Scrooge McDuck"
scrooge.fullName = "Scrooge H. McDuck"
print(scrooge.fullName) // returns "Scrooge H. McDuck"
Example #5: private(set)
variable property
示例 5:private(set)
变量属性
/* Duck.swift located in Sources folder */
protocol FullyNamed {
var fullName: String { get }
}
public struct Duck: FullyNamed {
public private(set) var fullName: String
public init(fullName: String) {
self.fullName = fullName
}
public mutating func renameWith(fullName: String) {
self.fullName = fullName
}
}
/* Playground file */
var scrooge = Duck(fullName: "Scrooge McDuck")
print(scrooge.fullName) // returns "Scrooge McDuck"
scrooge.renameWith("Scrooge H. McDuck")
print(scrooge.fullName) // returns "Scrooge H. McDuck"
Apple also states:
苹果还表示:
If a protocol requires a property to be gettable and settable, that property requirement cannot be fulfilled by a constant stored property or a read-only computed property.
如果协议要求属性是可获取和可设置的,那么常量存储属性或只读计算属性无法满足该属性要求。
For this reason, the two following Playground code snippets ARE NOTvalid:
出于这个原因,以下两个游乐场代码片段不有效:
Example #1: constant property
示例 #1:常量属性
protocol FullyNamed {
var fullName: String { get set }
}
struct Duck: FullyNamed {
let fullName: String
}
let scrooge = Duck(fullName: "Scrooge McDuck")
// Error message: Type 'Duck' does not conform to protocol 'FullyNamed'
Example #2: computed property (get only)
示例#2:计算属性(仅限获取)
protocol FullyNamed {
var fullName: String { get set }
}
struct Duck: FullyNamed {
private var name: String
var fullName: String {
return name
}
}
var scrooge = Duck(name: "Scrooge McDuck")
// Error message: Type 'Duck' does not conform to protocol 'FullyNamed'
Example #3: computed property (get only)
示例 #3:计算属性(仅限获取)
protocol FullyNamed {
var fullName: String { get }
}
struct Duck: FullyNamed {
var fullName: String {return "Scrooge McDuck"}
init(fullName: String) {
self.fullName = fullName
// Error Message Cannot assign to Property: "FullName" is get only
}
}
回答by Patrick Goley
Consider the following:
考虑以下:
var testDto = ModelDto(modelId: 1)
var testDto = ModelDto(modelId: 1)
The variable testDto
type here is known to be ModelDto
. ModelDto
is known to have a mutable variable var objectId: Int
. You're free to modify objectId because you're accesses the object through the ModelDto
interface and not via the protocol interface where it is only gettable.
testDto
已知这里的变量类型是ModelDto
. ModelDto
已知有一个可变变量var objectId: Int
。您可以自由修改 objectId,因为您是通过ModelDto
接口访问对象,而不是通过协议接口访问它,因为它只能获取。
Try the following:
请尝试以下操作:
var testDto: DataTransferObject = ModelDto(modelId: 1)
testDto.objectId = 2 // compiler error
The above example shouldn't compile. Because the type of testDto
is only known to be DataTransferObject
, we don't know that the underlying implementation has a settable property. We only know about the gettable property declared in the protocol.
上面的例子不应该编译。因为 的类型testDto
只知道是DataTransferObject
,所以我们不知道底层实现有一个可设置的属性。我们只知道协议中声明的 gettable 属性。
In short, you've declared ModelDto
to have a get/set variable, so it would be quite strange indeed if Swift did notlet you set it. Having a get only variable would rely on you referncing the object via the protocol or changing objectId
on ModelDTO
to be a let variable.
总之,你已经宣布ModelDto
拥有的get / set变量,所以这将是非常奇怪了,如果斯威夫特也没有让你设置。有一个GET变量只将依靠您通过协议referncing对象或改变objectId
上ModelDTO
是一个让变量。
EDIT: To address your confusion about why ModelDto
is allowed to have a settable variable. It is the same as how ModelDto
is allowed to have other functions than the ones defined in the protocol. Getters and setters are actually just functions, so the protocol requiring a getter does not preclude an implementation from also having a setter. The same is possible in Objective C. Protocols are descriptive, not restrictive.
编辑:为了解决您对为什么ModelDto
允许具有可设置变量的困惑。与如何ModelDto
允许具有协议中定义的功能之外的其他功能相同。getter 和 setter 实际上只是函数,所以需要 getter 的协议并不排除实现也有 setter。在目标 C 中也是如此。协议是描述性的,而不是限制性的。
回答by Honey
I'm answering the question in it's generic sense.
我是从一般意义上回答这个问题的。
Before addressing the question you must know what does get
& set
mean.
解决这个问题之前,你必须知道什么呢get
&set
意思。
(If you'r coming from an Objective-C world:) get
means readOnly, that is I'm allowed to know the number of legs an animal has. I'm not allowed to set it. get
& set
together means readWriteie I'm allowed to know the weight of an animal while I'm also able to set/change the weight of an animal
(如果您来自 Objective-C 世界:)get
表示readOnly,也就是说我可以知道动物的腿数。我不允许设置它。get
& set
together 表示readWrite即我可以知道动物的重量,同时我也可以设置/更改动物的重量
With the following example.
用下面的例子。
protocol Animal {
var weight : Int { get set }
var limbs : Int { get }
}
If you only have getter, and attempt to hide setter (by using private (set)
... then you WON'T get an error ... it's likely what you wanted and how it must be done!
如果您只有 getter,并尝试隐藏 setter(通过使用private (set)
...,那么您不会收到错误...这可能是您想要的以及必须如何完成的!
Likely what you intended:
可能是你的意图:
class Cat : Animal {
private (set) var limbs: Int = 4 // This is what you intended, because you only have get requirements...and don't want any conforming type to be able to set it ie don't want others do catInstance.limbs = 22
var weight: Int = 15
}
var smallCat = Cat()
smallCat.weight = 20 // Good!
// attempting to set it will create an error!!!
smallCat.limbs = 5 // Error: Cannot assign to property: 'limbs' setter is inaccessible
Likely what you didn't intend:
可能是你不想要的:
class Panda : Animal {
var limbs: Int = 4 // This is OK, but it kinda defeats the purpose of it being a get only
var weight: Int = 200
}
var littlPanda = Panda()
littlPanda.weight = 40 // Good
littlPanda.limbs = 30 // NO Error!!! Likely unintended
Basically with {get}
there is still some extrawork to be done which the compiler doesn'ttell you ... YOU must add private (set)
to achieve the intended behavior
基本上{get}
还有一些额外的工作要做,编译器没有告诉你......你必须添加private (set)
才能实现预期的行为
If your property has setter and you attempt to hide setter then you will actually see an error.
如果您的属性有 setter 并且您尝试隐藏 setter,那么您实际上会看到一个错误。
class Dog : Animal {
private (set) var limbs: Int = 4
private (set) var weight: Int = 50 // Error: Setter for property 'weight' must be declared internal because it matches a requirement in internal protocol 'Animal'
}
You're not allowed to hide, because you promised to provide a setter...
你不能隐藏,因为你承诺提供一个二传手......
回答by erdekhayser
In your class, you create a stored property named objectId
. In your protocol, you specify that the property needs a getter –?that is its only requirement.
在您的类中,您创建了一个名为 的存储属性objectId
。在您的协议中,您指定该属性需要一个 getter——这是它的唯一要求。
If you wanted it to be a computer property, like you expect it to, you need to declare objectId
with the following:
如果您希望它像您期望的那样成为计算机属性,则需要objectId
使用以下内容进行声明:
var objectId: Int{ return (someNumber) }
Without the closure to compute the value, it is, by default, a stored property.
没有计算值的闭包,默认情况下,它是一个存储属性。
回答by omaraguirre
The behavior you are seeing on your code sample is called member hiding. Member hiding happens in object oriented languages when new a member is declared with the same name or signature of an inherited one, so by having:
var objectId: Int
in your struct implementation, you are effectively creating a new member called objectId and hiding the property inherited from the protocol.
您在代码示例中看到的行为称为成员隐藏。成员隐藏发生在面向对象的语言中,当新成员声明为具有继承成员的相同名称或签名时,因此通过:
var objectId: Int
在您的结构实现中,您有效地创建了一个名为 objectId 的新成员并隐藏了从协议继承的属性.
In order to honor the contract between your struct and your protocol, objectIdcould be declared as:
为了遵守结构和协议之间的契约,可以将objectId声明为:
let objectId: Int = 1
or
或者
var objectId: Int {
get {
return 1
}
}