英文:
Mutability of a class after conforming to protocol is in question
问题
I was trying to implement a Networking Module for my personal project and I was following TDD. When I am writing the test cases I came across a compile error and I was not able to map the error with Swift concepts. I could have easily ignored it and done the implementation in a different way. But I was not feeling right to do it as I want to know the exact reason for the error.
这段代码中,我试图为我的个人项目实现一个网络模块,并且我在遵循测试驱动开发(TDD)的过程中遇到了一个编译错误,但我无法将这个错误与Swift的概念联系起来。我本可以轻松地忽略它,并以不同的方式进行实现。但是,我并不希望这样做,因为我想要知道错误的确切原因。
This is the code snippet.
这是代码片段。
import UIKit
protocol HTTPClient {
var url: String? {get set}
func load()
}
class HTTPClientSpy: HTTPClient {
var url: String?
func load() {
}
}
class Feed {
let client: HTTPClient
init(client: HTTPClient) {
self.client = client
}
func loadFeed() {
client.url = "" //Compile Error -> Cannot assign to property: 'client' is a 'let' constant
client.load()
}
}
When I do the following change the error goes away
当我做以下更改时,错误消失了
class Feed {
let client: HTTPClientSpy
init(client: HTTPClientSpy) {
self.client = client
}
func loadFeed() {
client.url = "" //No compile errors
client.load()
}
}
Swift classes are mutable, which means we should be able to change the properties of the instance even if we create a constant reference to the instance. It seems there is something to do with the protocol conformance in this case which I cannot understand.
Swift的类是可变的,这意味着即使我们创建了对实例的常量引用,我们仍应该能够更改实例的属性。在这种情况下,似乎与协议的遵循有关,这一点我无法理解。
Can someone please explain the theory behind this?
请有人解释一下背后的理论吗?
英文:
I was trying to implement a Networking Module for my personal project and I was following TDD. When I am writing the test cases I came across a compile error and I was not able to map the error with Swift concepts. I could have easily ignored it and done the implementation in a different way. But I was not feeling right to do it as I want to know the exact reason to the error.
This is the code snippet.
import UIKit
protocol HTTPClient {
var url: String? {get set}
func load()
}
class HTTPClientSpy: HTTPClient {
var url: String?
func load() {
}
}
class Feed {
let client: HTTPClient
init(client: HTTPClient) {
self.client = client
}
func loadFeed() {
client.url = "" //Compile Error -> Cannot assign to property: 'client' is a 'let' constant
client.load()
}
}
When I do the following change the error goes away
class Feed {
let client: HTTPClientSpy
init(client: HTTPClientSpy) {
self.client = client
}
func loadFeed() {
client.url = "" //No compile errors
client.load()
}
}
Swift classes are mutable. which means we should be able to change the properties of the instance even if we create a constant reference to the instance. It seems there is something to do with the protocol conformance in this case which I cannot understand.
Can someone please explain the theory behind this?
答案1
得分: 3
Swift类是可变的,这意味着即使我们创建了对实例的常量引用,我们也应该能够更改实例的属性。
的确,你是对的。但是structs也可以符合你的HTTPClient
协议:
struct SomeStruct: HTTPClient {
var url: String?
func load() {}
}
如果Feed
接收了SomeStruct
的实例,那么client.url = ""
将不起作用。通常情况下,如果你使用let
声明了一个结构体类型的变量,你不能更改结构体变量的var
。
let client = SomeStruct()
client.url = "" // 错误
编译器不知道Feed
中的client
是存储一个结构体还是一个类,所以它试图确保安全,不允许你更改url
。
你可以通过添加 : AnyObject
来确保只有类才能符合该协议:
protocol HTTPClient: AnyObject {
// ...
}
英文:
> Swift classes are mutable. which means we should be able to change the properties of the instance even if we create a constant reference to the instance.
Indeed you are right. But structs can conform to your HTTPClient
protocol too:
struct SomeStruct: HTTPClient {
var url: String?
func load() {}
}
If Feed
were passed an instance of SomeStruct
, then client.url = ""
would not work. Normally you cannot change the var
s of a struct-typed variable, if you declared the variable with let
.
let client = SomeStruct()
client.url = "" // error
The compiler doesn't know whether client
in Feed
is storing a struct or a class, so it tries to be safe and doesn't let you change url
.
You can make sure that only classes can conform to the protocol by adding : AnyObject
:
protocol HTTPClient: AnyObject {
// ...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论