Динамическая инициализация enum на основе ассоциированного значения - PullRequest
0 голосов
/ 09 октября 2019

Это мое перечисление:

enum E {
    case a(Int), b(String)
}

Типы значений, связанные с enum, уникальны и всегда точно один.

Допустим, у меня есть эта переменная:

let myInt = 0

Я хочу создать экземпляр E на основе переменной myInt, , динамически . Это должно привести к:

E.a(0)

Но в «реальном мире» я не знаю, какую собственность я получу. Я знаю только одно: я могу инициализировать enum E с ним. Мне нужно динамически инициализировать перечисление, основанное на значении свойства. В настоящее время у меня есть огромное переключение на свойство для инициализации перечисления, я не хочу этого.

Но я понятия не имею, как выполнить эту задачу. Я попытался отразить тип enum, но у меня сложный тип, и я понятия не имею, как продолжить его инициализацию, даже если я знаю типы.

Итак, я получаю свойство определенного типа. Я знаю, что определенный тип совпадает с регистром в enum E, потому что существует ровно один случай, ассоциированное значение которого соответствует типу свойства. Я хочу инициализировать экземпляр этого перечисления этим случаем со значением свойства.

Ответы [ 2 ]

1 голос
/ 09 октября 2019

Если вашей единственной отправной точкой является тип того, что в конечном итоге будет ассоциированным значением, вы можете использовать оператор switch:

enum E {
    case a(Int)
    case b(String)

    init(associatedValue: Any) {
        switch associatedValue {
        case is Int:
            self = .a(associatedValue as! Int)
        case is String:
            self = .b(associatedValue as! String)
        default:
            fatalError("Unrecognized type!")
        }
    }
}

let response = E(associatedValue: 1) // .a(1)
let other = E(associatedValue: "haha!") // .b("haha!")

Проблема в том, что этот переключатель должен быть исчерпывающим, то есть охватывать все типы. Таким образом, вам нужен либо наземный кейс (.unreachable(Any)), либо fatalError, чтобы вы могли поймать их в разработке.

1 голос
/ 09 октября 2019

Вы можете использовать пользовательский инициализатор: (Я использовал более описательные имена)

enum TypeFinder {
    case int(Int)
    case string(String)
    case unknown(Any)

    init(value: Any) {
        switch value {
        case let v as Int: self = .int(v)
        case let v as String: self = .string(v)
        default: self = .unknown(value)
        }
    }
}

Тестирование:

var unknownTypeValue: Any = "Testing.."

print(TypeFinder(value: unknownTypeValue))

unknownTypeValue = 1234

print(TypeFinder(value: unknownTypeValue))

unknownTypeValue = true

print(TypeFinder(value: unknownTypeValue))
...