Как реализовать CustomStringConvertible в перечислении, отличном от RawRepresentable, в соответствии с протоколом? - PullRequest
2 голосов
/ 07 мая 2020

Рассмотрим следующий код, который состоит из:

  • протокола, 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 было бы намного чище.

...