РЕШАЕМАЯ — Swift Enum — преобразование вложенных перечислений в строку Enum для разрешения .rawValue

#swift #string #enums #nested #return-value

#swift #строка #перечисления #вложенный #возвращаемое значение

Вопрос:

РЕШАЕМАЯ

Спасибо @New Dev и @Joakim Danielson за вашу помощь. Я использовал ответ @Joakim Danielson, чтобы улучшить свой код.

У меня есть метод расширения для назначения идентификаторов доступности представлениям на основе заданного строкового перечисления. Я обновил метод, чтобы напрямую принимать случаи перечисления строк в качестве параметра, тем самым ПОЛНОСТЬЮ устраняя необходимость в классе перечисления AccessibilityId, как показано ниже, потрясающе!

Изменения

Перед:

 .accessibility(identifier: .home(.clickButton))

// Simplified for StackOverflow.
// Imagine 20 more cases..
enum AccessibilityId { 
    case home(HomeId)
    
    var rawValue: String {
        switch self {
        case .home(let id):
            return id.rawValue
        }
    }
}

extension View {
    func accessibility(identifier: AccessibilityId) -> ModifiedContent<Self, AccessibilityAttachmentModifier> {
        self.accessibility(identifier: identifier.rawValue)
    }
}
 

После:

 .accessibility(identifier: HomeId.clickButton)

extension View {    
    func accessibility<T: RawRepresentable>(identifier: T) -> ModifiedContent<Self, AccessibilityAttachmentModifier> where T.RawValue == String {
        self.accessibility(identifier: identifier.rawValue)
    }
}
 

—————————————————————

Оригинальный вопрос

Что у меня есть

 enum Item {
    case animal(AnimalId)
    case vehicle(VehicleId)
    case food(FoodId)
    
    var rawValue: String {
        switch self {
        case .animal(let id):
            return id.rawValue
        case .vehicle(let id):
            return id.rawValue
        case .food(let id):
            return id.rawValue
        }
    }
}

enum AnimalId: String {
    case cat
    case dog
}

// etc.
// Imagine more cases and more enums.
 

Чего я хочу

 enum Item {
    case animal(AnimalId)
    case vehicle(VehicleId)
    case food(FoodId)
    
    var rawValue: String {
        switch self {
        case self as StringEnum:
            return id.rawValue
        default:
            return ""
        }
    }
}
 

Использование

 func test() {
   foo(.animal(.cat))
   foo(.vehicle(.plane))
   foo(.food(.tacos))
}

func foo(_ item: Item) {
   print(item.rawValue)
}
 

Я доволен использованием, но я бы хотел уменьшить количество повторяющихся случаев в данном операторе switch . Обратите внимание, как все они имеют return id.rawValue . Приведенное выше — всего лишь пример, на самом деле у меня около 30 случаев.

Мой вопрос

Есть ли у меня способ перехватить все вложенные строковые перечисления одним переключателем или разрешить регистр, чтобы уменьшить дублирующийся код, который я должен написать, без потери предполагаемого использования?

Спасибо за ваши усилия, я надеюсь найти улучшение для моего кода!

Комментарии:

1. Значит, Animal и AnimalID — это одно и то же?

2. Каковы определения AnimalId и тому подобное?

3. Ах да, @JoakimDanielson! Мой плохой, я отредактировал свой вопрос, спасибо!

4. @Alexander AnimalID, VehicleId и FoodId — это все строковые перечисления с простыми случаями, такими как «case cat, case dog, case car, case fruit» все, что вы можете себе представить, никаких других переменных или методов, связанных с этим вопросом.

Ответ №1:

Вот решение, которое основано не на том, что Item является перечислением, а на общей структуре

 struct Item<T: RawRepresentable> where T.RawValue == String {
    let thing: T

    var rawValue: String {
        thing.rawValue
    }
}
 

С помощью этого решения вам не нужно изменять другие ваши перечисления.
Пример

 let item1 = Item(thing: AnimalId.cat)
let item2 = Item(thing: VehicleId.car)
print(item1.rawValue, item2.rawValue)
 

выводит

cat car

Комментарии:

1. Спасибо вам за ваше предложение, основываясь на нем, мне удалось найти решение для своих нужд. Я обновил свой вопрос / сообщение, чтобы отразить мои изменения! Я принял ваш ответ!

Ответ №2:

Вам нужно что-то общее между всеми этими связанными значениями, например, соответствие общему протоколу, например protocol RawStringValue :

 protocol RawStringValue {
   var rawValue: String { get }
}

// String enums already conform without any extra implementation
extension AnimalId: RawStringValue {} 
extension VehicleId: RawStringValue {}
extension FoodId: RawStringValue {}
 

Тогда вы могли бы создать switch self внутри вот так:

 var rawValue: String {
   switch self {
   case .animal  (let id as RawStringValue),
        .vehicle (let id as RawStringValue),
        .food    (let id as RawStringValue):
      return id.rawValue
   }
}
 

При этом enum со связанными значениями — не самый удобный тип для работы, поэтому убедитесь, что это правильный выбор.

Комментарии:

1. Спасибо за предложение. Приятно видеть автоматическое соответствие RawStringValue, это приятно. И я рад видеть, что можно позволить случаям провалиться, приведя их к одному и тому же протоколу! Но я пока не удовлетворен. Существует ли тип или класс, к которому можно привести перечисление строк без введения протокола?