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
用于任何具有合理编码作为字符串的类型。例如,它应该适用于 Int
、String
(嗯,嗯),理想情况下,任何 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
}
我想要一个 GenericThing
模板参数,它是可以合理地与字符串相互转换的任何类型。
// ConvertsToAndFromString is a made up protocol here – what should I use instead?
struct GenericThing<Id: ConvertsToAndFromString> {
}
然后我应该能够将 GenericThing
用于任何具有合理编码作为字符串的类型。例如,它应该适用于 Int
、String
(嗯,嗯),理想情况下,任何 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
}