Swift协议仅能设置?

发布于 2025-02-03 18:26:24 字数 706 浏览 2 评论 0原文

为什么我可以在没有任何错误的情况下执行此操作:

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定义),那么我为什么还要使用它们?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

九歌凝 2025-02-10 18:26:24

苹果在“ nofollow noreferrer”>“ swift noreferrer“>” /a>:

如果该协议仅要求属性可获得,则可以通过任何类型的属性来满足要求,并且如果这对您自己的代码很有用,则该属性也有效。

因此,以下五个游乐场代码片段都是有效的:

示例#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:计算属性(get and set)

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) varible属性

/* 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也指出:

如果协议要求属性是可获取且可设置的,则该属性要求无法通过恒定的存储属性或仅读取的属性来满足。

因此,以下两个游乐场代码片段不是有效:

示例#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:computed属性(仅获取)

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
    }
}

Apple states in the "Swift Programming Languages Documentation":

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:

Example #1: constant property

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

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)

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)

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

/* 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 NOT valid:

Example #1: constant property

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)

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)

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
    }
}
栀子花开つ 2025-02-10 18:26:24

根据

”可以通过多种方式来满足二阶要求。如果属性声明同时包括GET和SET关键字,则符合类型可以通过存储的变量属性或既可以读取又可写入的计算属性实现它(也就是说,可以同时实现Getter和Setter)。但是,该属性声明不能作为常量属性或仅读取的属性实现。 如果属性声明仅包含GET关键字,则可以将其实现为任何类型的属性。

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.

忆离笙 2025-02-10 18:26:24

请考虑以下内容:

var testdto = modeldto(modelID:1)

变量testdto键入此处已知为modeldtomodeldto已知具有可变变量var objectId:int。您可以自由修改ObjectID,因为您可以通过modeldto接口访问对象,而不是通过仅可获取的协议接口访问对象。

尝试以下内容:

var testDto: DataTransferObject = ModelDto(modelId: 1)
testDto.objectId = 2 // compiler error

上面的示例不应编译。由于testdto的类型仅是dataTransferObject,因此我们不知道基础实现具有可设置的属性。我们只知道协议中声明的可获取属性。

简而言之,您已声明modeldto具有一个get/set变量,因此,如果Swift dod dop not 让您设置它,那确实是非常奇怪的。只有一个get变量将依靠您通过协议或更改objectId on modeldto作为让变量来引用对象。

编辑:要解决您为什么Modeldto具有设置变量的困惑。它与modeldto的其他功能相同,而不是协议中定义的功能。 Getters和Setter实际上只是功能,因此需要GETETER的协议并不排除实现设置器的实现。目标C中的可能性也是如此。协议具有描述性,而不是限制性。

Consider the following:

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.

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.

In short, you've declared ModelDto to have a get/set variable, so it would be quite strange indeed if Swift did not let 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.

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.

何以畏孤独 2025-02-10 18:26:24

我正在以一般意义回答这个问题。

在解决问题之前,您必须知道get& SET平均值。

(如果您来自Objective-C World :) 获取表示 ReadOnly ,那我可以知道动物的腿部数量。我不允许设置它。 get& set共同表示 readwrite 即,我可以知道动物的重量,而我也可以

通过以下示例设置/更改动物的重量。

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

​em>要完成的工作,编译器不告诉您...您必须添加private(set)以实现预期的行为,


如果您的属性有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'
}

I'm answering the question in it's generic sense.

Before addressing the question you must know what does get & set mean.

(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 readWrite ie I'm allowed to know the weight of an animal while I'm also able to set/change the weight of an animal

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!

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 extra work to be done which the compiler doesn't tell you ... YOU must add private (set) to achieve the intended behavior


If your property has setter and you attempt to hide setter then you will actually see an error.

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...

醉生梦死 2025-02-10 18:26:24

您在代码样本上看到的行为称为成员隐藏。当新成员以相同的名称或继承的签名声明新成员时,成员隐藏在面向对象的语言中发生,因此可以通过:
var objectId:int
在您的结构实现中,您正在有效地创建一个名为ObjectID的新成员,并隐藏从协议中继承的属性。

为了纪念您的结构与协议之间的合同, objectid 可以声明为:

  let objectId: Int = 1

var objectId: Int {
        get {
            return 1
        }
    }

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.

In order to honor the contract between your struct and your protocol, objectId could be declared as:

  let objectId: Int = 1

or

var objectId: Int {
        get {
            return 1
        }
    }
东京女 2025-02-10 18:26:24

在您的课程中,您创建了一个名为Objectid的存储属性。在您的协议中,您指定属性需要一个getter -  这是它的唯一要求。

如果您希望它像您期望的那样是计算机属性,则需要声明objectId,其中以下内容:

var objectId: Int{ return (someNumber) }

没有闭合即可计算该值,默认情况下,它是存储的属性。

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.

If you wanted it to be a computer property, like you expect it to, you need to declare objectId with the following:

var objectId: Int{ return (someNumber) }

Without the closure to compute the value, it is, by default, a stored property.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文