Рассмотрим следующий код, который состоит из:
- протокола,
P
- двух перечислений,
E0
и E1
, которые соответствуют P
- Функция
f(p:)
, которая принимает в качестве аргумента экземпляр P
import Foundation
protocol P { }
enum E0: P { case a }
enum E1: P { case b }
func f(p: P) {
print("\(type(of: p)).\(p)")
}
let e0_a = E0.a
let e1_b = E1.b
f(p: e0_a) // prints "E0.a"
f(p: e1_b) // prints "E1.b"
Я хотел бы иметь возможность распечатать строку, описывающую p
аргумент в форме:
"Name of type implementing P
. case of P
"
Как показано в функции f()
, это работает нормально, и я получаю желаемый результат.
Я бы хотел, если возможно, реализовать расширение CustomStringConvertible
для P
, которое генерирует ту же строку.
Возможно ли это?
Вот один из подходов, который не работает:
protocol P: CustomStringConvertible { }
extension P {
var description: String { return "\(type(of: self).\(self)" }
}
Это не работает, потому что \(self)
заставляет description
рекурсивно вызывать себя до тех пор, пока стек не переполнится.
Вот еще один подход, который не работает :
protocol P: CustomStringConvertible { }
extension P where Self: RawRepresentable {
var description: String { return "\(type(of: self)).\(self.rawValue)" }
}
Этот подход не работает, потому что E0
не RawRepresentable
. Под капотом есть некий magi c, который позволяет Swift печатать имя случая перечисления, даже если перечисление не имеет rawValue
, но я не уверен, как получить к нему доступ. Использование чего-то вроде Mirror(reflecting: p).description
выводит на печать тип p, а не имя случая перечисления.
Спасибо за любые идеи. Как я уже сказал, это можно сделать в функции, которая получает P
, но CustomStringConvertible
было бы намного чище.