Доступ к связанным значениям в массиве Swift Enum непрозрачным способом - PullRequest
1 голос
/ 13 января 2020

Я действительно не нашел то, что мне нужно в связанных вопросах. Это может быть потому, что я немного толстый и не видел его, но вот мое затруднение:

У меня есть вычисляемое свойство, которое возвращает массив перечислений со связанными значениями.

Все значения имеют одинаковые типы (в моем случае это тип "flag"), но перечисления разные.

Я бы хотел посмотреть, есть ли какой-нибудь способ циклически проходить через массив , глядя только на связанные значения, независимо от типа перечисления. Я прилагаю небольшую игровую площадку, которая показывает, что я имею в виду:

enum A {
    case valueA(Int)
    case valueB(Int)
    case valueC(Int)
}

let a: [A] = [.valueA(0), .valueB(1), .valueC(2)]

for each in a {
    print(String(describing: each))
}

print();

// This works:

for each in a {
    if case let .valueA(value) = each {
        print(value)
    }
    if case let .valueB(value) = each {
        print(value)
    }
    if case let .valueC(value) = each {
        print(value)
    }
}

print();

// So does this:

for each in a {
    var value: Int = 0

    switch each {
    case .valueA(let val):
        value = val

    case .valueB(let val):
        value = val

    case .valueC(let val):
        value = val
    }

    print(value)
}

// What I want:

//for each in a {
//    if case let A(value) = each {
//        print(value)
//    }
//}

Я хочу иметь возможность обрабатывать каждого члена коллекции, извлекать его флаг, а затем принимать решение на основе этого флага.

Я знаю, что мог бы сделать это с помощью большого оператора ol 'switch со всеми значениями enum (секунда go), но было бы неплохо, если бы существовал какой-то общий c способ простого доступа все значения.

Ответы [ 2 ]

2 голосов
/ 13 января 2020

Вам все равно придется проверять каждый случай, но вы можете сделать

enum A {
    case valueA(Int)
    case valueB(Int)
    case valueC(Int)
}

let a: [A] = [.valueA(0), .valueB(1), .valueC(2)]

for each in a {

    switch each {
    case .valueA(let val), .valueB(let val), .valueC(let val):
        print(val)
    }
}

Это все равно будет применяться, если у вас есть случаи со связанными значениями различных типов:

enum Cases {
    case one(Int)
    case two(Int)
    case three(Int, String)
    case four(String)
    case five(String)
}

let testArray = [Cases.one(1), .two(2), .three(3, "three"),
                 .four("four"), .five("five")]

// Matching associated Ints
for value in testArray {

    switch value {

    case .one(let intVal), .two(let intVal), .three(let intVal, _):
        print(intVal)

    case .four(let strVal), .five(let strVal):
        print(strVal)
    }
}

// Matching associated Strings
for value in testArray {

    switch value {

    case .one(let intVal), .two(let intVal):
        print(intVal)

    case .three(_, let strVal), .four(let strVal), .five(let strVal):
        print(strVal)
    }

}

// Matching any type, cast to Any
for value in testArray {

    switch value {
    case .one(let anyVal as Any), .five(let anyVal as Any):
        print(anyVal)

    default:
        continue // skipping these cases
    }
}

Важным выводом является то, что вы связываете одни и те же имена переменных в каждом выражении, значение которого вы пытаетесь сопоставить, а это означает, что вы не можете сопоставить значения, которые недоступны ни в одном утверждении:

switch ... {

// This won't work, because myInt is not defined in case .two 
// and myOtherInt isn't defined in case .one

case .one(let myInt), .two(let myOtherInt):
...

} 

Кому добавьте к ответу @ Kiril, если вы хотите, чтобы вычисленные значения были для случаев с различными типами связанных значений, вы можете определить необязательные вычисляемые переменные, которые будут возвращать эти значения:

extension Cases {

    var intValue: Int? {

        switch self {

        case .one(let myInt), .two(let myInt), .three(let myInt, _):
            return myInt

        default:
            return nil
        }
    }

    var strValue: String? {

        switch self {

        case .three(_, let myStr), .four(let myStr), .five(let myStr):

            return myStr

        default:
            return nil
        }
    }
}
1 голос
/ 13 января 2020

Я бы предложил небольшое изменение вашего перечисления:

enum A {
    case valueA(Int)
    case valueB(Int)
    case valueC(Int)

    var flag: Int {
        switch self {
        case .valueA(let flag),
             .valueB(let flag),
             .valueC(let flag):
            return flag
        }
    }
}

Это делает любой l oop, которому просто нужен флаг, тривиальным:

for each in a {
   print(each.flag)
}
...