簡體   English   中英

使用協議類型屬性對結構進行解碼/編碼

[英]Decoding/Encoding a struct with protocol type properties

我正在嘗試使用UserDefaults保存配置數據結構,因此數據結構需要符合Codable協議。 這是我的數據結構:

// Data structure which saves two objects, which conform to the Connection protocol
struct Configuration {
    var from: Connection
    var to: Connection
}

protocol Connection: Codable {
    var path: String { get set }
}


// Two implementations of the Connection protocol
struct SFTPConnection: Connection, Codable {
    var path: String
    var user: String
    var sshKey: String
}

struct FTPConnection: Connection, Codable {
    var path: String
    var user: String
    var password: String
}

如果我只是將Codable添加到Configuration ,它將不起作用。 所以我必須自己實現它。

extension Configuration: Codable {

    enum CodingKeys: String, CodingKey {
        case from, to
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        let from = try container.decode(Connection.self, forKey: .from)
        let to = try container.decode(Connection.self, forKey: .to)

        self.from = from
        self.to = to
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)

        try container.encode(from, forKey: .from)
        try container.encode(to, forKey: .to)
    }
}

對於decode()encode()每次調用,我都會收到錯誤Protocol type 'Connection' cannot conform to 'Decodable/Encodable' because only concrete types can conform to protocols

我可以看到編譯器很難識別,應該使用哪個類來解碼給定的對象。 但我認為對對象進行編碼應該很容易,因為Connection類型的每個對象都實現了encode()方法。

我知道,問題出在協議上,並且該協議不能與Decodable/Encodable一起使用。 我將如何更改decode/encode的代碼,以便我仍然可以將協議與各種實現一起使用? 我的猜測是以某種方式告訴decode/encode要使用的協議實現。 我很感激這個問題的任何優雅的解決方案!

Swift 的一個限制是協議不能符合自身。 因此fromto不符合Codable看起來很奇怪。

您可以通過使用泛型來繞過它,這基本上意味着您將fromto聲明為符合Codable任意類型。 就是這樣:

struct Configuration<F: Connection, T: Connection>: Codable {
    var from: F
    var to: T
}


let myFrom = SFTPConnection(path: "foo", user: "me", sshKey: "hgfnjsfdjs")
let myTo = FTPConnection(path: "foo", user: "me", password: "hgfnjsfdjs")
let example = Configuration(from: myFrom, to: myTo)

所以FT是符合Connection類型。 當您在最后一行實例化example時,編譯器推斷FSFTPConnectionTFTPConnection

一旦我添加了通用參數, Configuration就能夠在沒有擴展的情況下綜合符合Codable


要回答Sh_kahn的大約有兩個通用的參數來看,我這樣做是為了讓fromto是兩種不同類型的連接。 如果您總是希望兩個連接的類型相同,即總是兩個SFTPConnection或兩個FTPConnection您應該像這樣聲明Configuration

struct Configuration<C: Connection>: Codable {
    var from: C
    var to: C
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM