Swift 协议只能设置?
Swift Protocol get only settable?
为什么我可以毫无错误地执行此操作:
var testDto = ModelDto(modelId: 1)
testDto.objectId = 2
当我定义这个时:
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()
}
}
如果我的协议中的定义大部分被忽略(getter、setter 定义),我为什么还要使用它们?
在您的 class 中,您创建了一个名为 objectId
的存储 属性。在您的协议中,您指定 属性 需要 getter – 这是它唯一的要求。
如果您希望它成为一台计算机 属性,就像您期望的那样,您需要使用以下内容声明 objectId
:
var objectId: Int{ return (someNumber) }
没有计算值的闭包,默认情况下,它是一个存储的 属性。
getter 和 setter 要求可以通过多种方式通过符合类型来满足。如果 属性 声明同时包含 get 和 set 关键字,则符合类型可以使用存储变量 属性 或可读可写的计算 属性 来实现它(即,一个实现了 getter 和 setter)。但是,属性 声明不能实现为常量 属性 或只读计算 属性。 如果 属性 声明只包含 get 关键字,它可以实现为任何类型的 属性。
您在代码示例中看到的行为称为成员隐藏。当使用与继承成员相同的名称或签名声明新成员时,成员隐藏发生在面向对象的语言中,因此具有:
var objectId: Int
在您的结构实现中,您有效地创建了一个名为 objectId 的新成员并隐藏了从协议继承的 属性。
为了遵守结构和协议之间的契约,objectId 可以声明为:
let objectId: Int = 1
或
var objectId: Int {
get {
return 1
}
}
Apple 在 "Swift Programming Language (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.
因此,以下五个 Playground 代码片段都是有效的:
示例 #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"
示例 #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"
示例 #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"
示例 #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"
示例 #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 还声明:
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.
因此,以下两个 Playground 代码片段不有效:
示例 #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'
示例 #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'
示例 #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
}
}
考虑以下因素:
var testDto = ModelDto(modelId: 1)
这里的变量testDto
类型已知为ModelDto
。 ModelDto
已知有一个可变变量 var objectId: Int
。您可以自由修改 objectId,因为您是通过 ModelDto
接口访问该对象,而不是通过它只能获取的协议接口。
尝试以下操作:
var testDto: DataTransferObject = ModelDto(modelId: 1)
testDto.objectId = 2 // compiler error
上面的例子不应该编译。因为testDto
的类型只知道是DataTransferObject
,我们不知道底层实现有一个可设置的属性。我们只知道协议中声明的gettable 属性。
简而言之,您已经声明 ModelDto
有一个 get/set 变量,所以如果 Swift 没有 没有 [=39] 确实会很奇怪=] 让你设置它。拥有一个仅获取变量将依赖于您通过协议引用对象或将 ModelDTO
上的 objectId
更改为 let 变量。
编辑:为了解决您对为什么允许 ModelDto
具有可设置变量的困惑。这与允许 ModelDto
具有协议中定义的功能之外的其他功能相同。 Getters 和 setter 实际上只是函数,因此需要 getter 的协议并不排除实现也具有 setter。在 Objective C 中也是可能的。协议是描述性的,而不是限制性的。
我是在一般意义上回答这个问题。
在回答这个问题之前,您必须知道 get
和 set
是什么意思。
(如果您来自 Objective-C 世界:) get
表示 readOnly,也就是说我可以知道动物有的腿。我不允许设置它。 get
和 set
一起意味着 readWrite 即我可以知道动物的重量,同时我也可以 set/change 重量动物
用下面的例子。
protocol Animal {
var weight : Int { get set }
var limbs : Int { get }
}
如果您只有 getter,并尝试隐藏 setter(通过使用 private (set)
...那么您不会收到错误...这可能是您想要以及必须如何完成!
可能是您想要的:
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
可能是您不想要的:
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
基本上 {get}
还有一些 额外的 工作要做,编译器 不会 告诉你。 .. 您必须添加 private (set)
才能实现预期的行为
如果你的 属性 有 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'
}
你不能隐藏,因为你答应提供 setter...
为什么我可以毫无错误地执行此操作:
var testDto = ModelDto(modelId: 1)
testDto.objectId = 2
当我定义这个时:
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()
}
}
如果我的协议中的定义大部分被忽略(getter、setter 定义),我为什么还要使用它们?
在您的 class 中,您创建了一个名为 objectId
的存储 属性。在您的协议中,您指定 属性 需要 getter – 这是它唯一的要求。
如果您希望它成为一台计算机 属性,就像您期望的那样,您需要使用以下内容声明 objectId
:
var objectId: Int{ return (someNumber) }
没有计算值的闭包,默认情况下,它是一个存储的 属性。
getter 和 setter 要求可以通过多种方式通过符合类型来满足。如果 属性 声明同时包含 get 和 set 关键字,则符合类型可以使用存储变量 属性 或可读可写的计算 属性 来实现它(即,一个实现了 getter 和 setter)。但是,属性 声明不能实现为常量 属性 或只读计算 属性。 如果 属性 声明只包含 get 关键字,它可以实现为任何类型的 属性。
您在代码示例中看到的行为称为成员隐藏。当使用与继承成员相同的名称或签名声明新成员时,成员隐藏发生在面向对象的语言中,因此具有:
var objectId: Int
在您的结构实现中,您有效地创建了一个名为 objectId 的新成员并隐藏了从协议继承的 属性。
为了遵守结构和协议之间的契约,objectId 可以声明为:
let objectId: Int = 1
或
var objectId: Int {
get {
return 1
}
}
Apple 在 "Swift Programming Language (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.
因此,以下五个 Playground 代码片段都是有效的:
示例 #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"
示例 #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"
示例 #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"
示例 #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"
示例 #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 还声明:
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.
因此,以下两个 Playground 代码片段不有效:
示例 #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'
示例 #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'
示例 #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
}
}
考虑以下因素:
var testDto = ModelDto(modelId: 1)
这里的变量testDto
类型已知为ModelDto
。 ModelDto
已知有一个可变变量 var objectId: Int
。您可以自由修改 objectId,因为您是通过 ModelDto
接口访问该对象,而不是通过它只能获取的协议接口。
尝试以下操作:
var testDto: DataTransferObject = ModelDto(modelId: 1)
testDto.objectId = 2 // compiler error
上面的例子不应该编译。因为testDto
的类型只知道是DataTransferObject
,我们不知道底层实现有一个可设置的属性。我们只知道协议中声明的gettable 属性。
简而言之,您已经声明 ModelDto
有一个 get/set 变量,所以如果 Swift 没有 没有 [=39] 确实会很奇怪=] 让你设置它。拥有一个仅获取变量将依赖于您通过协议引用对象或将 ModelDTO
上的 objectId
更改为 let 变量。
编辑:为了解决您对为什么允许 ModelDto
具有可设置变量的困惑。这与允许 ModelDto
具有协议中定义的功能之外的其他功能相同。 Getters 和 setter 实际上只是函数,因此需要 getter 的协议并不排除实现也具有 setter。在 Objective C 中也是可能的。协议是描述性的,而不是限制性的。
我是在一般意义上回答这个问题。
在回答这个问题之前,您必须知道 get
和 set
是什么意思。
(如果您来自 Objective-C 世界:) get
表示 readOnly,也就是说我可以知道动物有的腿。我不允许设置它。 get
和 set
一起意味着 readWrite 即我可以知道动物的重量,同时我也可以 set/change 重量动物
用下面的例子。
protocol Animal {
var weight : Int { get set }
var limbs : Int { get }
}
如果您只有 getter,并尝试隐藏 setter(通过使用 private (set)
...那么您不会收到错误...这可能是您想要以及必须如何完成!
可能是您想要的:
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
可能是您不想要的:
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
基本上 {get}
还有一些 额外的 工作要做,编译器 不会 告诉你。 .. 您必须添加 private (set)
才能实现预期的行为
如果你的 属性 有 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'
}
你不能隐藏,因为你答应提供 setter...