swift 类在符合协议后的可变性是有问题的

5t7ly7z5  于 2023-05-16  发布在  Swift
关注(0)|答案(1)|浏览(111)

我试图为我的个人项目实现一个网络模块,我遵循TDD。当我写测试用例时,我遇到了一个编译错误,我无法用Swift概念Map错误。我本可以很容易地忽略它,并以不同的方式完成实现。但我觉得这样做不对,因为我想知道错误的确切原因。
这是代码片段。

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

当我做了下面的更改,错误就消失了

class Feed {
    let client: HTTPClientSpy

    init(client: HTTPClientSpy) {
        self.client = client
    }

    func loadFeed() {
        client.url = "" //No compile errors
        client.load()
    }
}

Swift类是可变的。这意味着我们应该能够改变示例的属性,即使我们创建了一个对示例的常量引用。在这种情况下,似乎与协议一致性有关,我无法理解。
有人能解释一下这背后的理论吗?

xqnpmsa8

xqnpmsa81#

Swift类是可变的。这意味着我们应该能够改变示例的属性,即使我们创建了一个对示例的常量引用。
你说得对。但是 structs 也可以符合HTTPClient协议:

struct SomeStruct: HTTPClient {
    var url: String?
    func load() {}
}

如果Feed传递了SomeStruct的一个示例,那么client.url = ""将无法工作。通常情况下,如果使用let声明变量,则不能更改结构类型变量的var

let client = SomeStruct()
client.url = "" // error

编译器不知道Feed中的client存储的是一个结构体还是一个类,所以它会尽量保证安全,不让你修改url
您可以通过添加: AnyObject来确保只有类才能符合协议:

protocol HTTPClient: AnyObject {
    // ...
}

相关问题