Как разрешить перекрывающиеся соответствия CustomStringConvertible
Основываясь на этой статье Джона Санделла, у меня есть следующая структура:
protocol Identifiable {
associatedtype RawIdentifier: Codable, Hashable = String
var id: Identifier<Self> { get }
}
struct Identifier<Value: Identifiable>: Hashable {
let rawValue: Value.RawIdentifier
init(stringLiteral value: Value.RawIdentifier) {
rawValue = value
}
}
extension Identifier: ExpressibleByIntegerLiteral
where Value.RawIdentifier == Int {
typealias IntegerLiteralType = Int
init(integerLiteral value: IntegerLiteralType) {
rawValue = value
}
}
Это может быть String или Int. Чтобы можно было просто распечатать (без использования.rawValue
), Я добавил следующие расширения:
extension Identifier: CustomStringConvertible where Value.RawIdentifier == String {
var description: String {
return rawValue
}
}
extension Identifier where Value.RawIdentifier == Int {
var description: String {
return "\(rawValue)"
}
}
Проблема в том, что он работает только для расширения, которое соответствует CustomStringConvertible, а другое игнорируется. И я не могу добавить соответствие к другому расширению, так как они будут перекрываться.
print(Identifier<A>(stringLiteral: "string")) // prints "string"
print(Identifier<B>(integerLiteral: 5)) // prints "Identifier<B>(rawValue: 5)"
1 ответ
Вы можете использовать один CustomStringConvertible
extension вместо двух, которые у вас есть на данный момент, независимо от типа:
extension Identifier: CustomStringConvertible {
var description: String {
"\(rawValue)"
}
}
Для меня это правильно печатает "строку", а затем "5" в соответствии с вашим последним примером кода.
По совпадению, это то, что Санделл делает в своей реализации Identity с открытым исходным кодом для Identifiable / Identifier - https://github.com/JohnSundell/Identity/blob/master/Sources/Identity/Identity.swift
Реализация Point-Free'Tagged' также заслуживает внимания: https://github.com/pointfreeco/swift-tagged/blob/master/Sources/Tagged/Tagged.swift