Swift 与字符串相互转换的协议

Swift protocol for things that convert to and from String

我想要一个 GenericThing 模板参数,它是可以合理地与字符串相互转换的任何类型。

// ConvertsToAndFromString is a made up protocol here – what should I use instead?
struct GenericThing<Id: ConvertsToAndFromString> {
}

然后我应该能够将 GenericThing 用于任何具有合理编码作为字符串的类型。例如,它应该适用于 IntString(嗯,嗯),理想情况下,任何 RawRepresentable 都可以,其中 RawValue 本身将与字符串相互转换。

示例:

enum Tubbies: String {
  case dipsy
  case laalaa
  case po
}

// I'd like to be able to do this.
let genericThing = GenericThing<Tubbies>

我不知道如何轻松地做到这一点。

我希望我可以使用 LosslessStringConvertible 而不是我编造的 ConvertsToAndFromString

我试过了,它适用于 Int 等。但它不适用于 Tubbies。我看不出让所有 RawRepresentable where RawValue: LosslessStringConvertible 也符合 LosslessStringConvertible.

的方法

这就是将 RawRespresentable 扩展为有条件 LosslessStringConvertible 的方式,具体取决于其 RawValue:

extension RawRepresentable where RawValue: LosslessStringConvertible {
    init?(_ rv: RawValue) {
        self.init(rawValue: rv)
    }

    var description: String { return self.rawValue.description }
}

这是实际操作:

struct GenericThing<Id: LosslessStringConvertible> {

}

enum Tubbies: String, LosslessStringConvertible {
    case dipsy
    case laalaa
    case po
}

let genericThing = GenericThing<Tubbies>()
print(Tubbies.po is LosslessStringConvertible) // => true

在 Swift 5.2 中至少有一个问题,扩展 RawRepresentable 导致 CodingKeys 编译失败。

public extension RawRepresentable where RawValue: LosslessStringConvertible {
    init?(_ rv: RawValue) { self.init(rawValue: rv) }
    var description: String { rawValue.description }
}

struct Test: Codable {
    public var test: String
    enum CodingKeys: String, CodingKey { // Error: Type 'Test.CodingKeys' does not conform to protocol 'CustomStringConvertible'
        case test = "foo"
    } 
}

我的解决方法是使用相同的策略显式添加一致性,它需要能够更改枚举但允许 CodingKeys 编译。

public protocol LosslessStringConvertibleEnum: LosslessStringConvertible, 
    RawRepresentable where RawValue: LosslessStringConvertible {}

public extension LosslessStringConvertibleEnum {
    init?(_ rawValue: RawValue) { self.init(rawValue: rawValue) }
    var description: String { rawValue.description }
}

enum Tubbies: String, LosslessStringConvertibleEnum {
    case dipsy
    case laalaa
    case po
}