Подтвердить что ты не робот

Могут ли связанные значения и необработанные значения сосуществовать в перечислении Swift?

В книге Swift есть примеры, демонстрирующие связанные значения и необработанные значения отдельно, есть ли способ определить перечисления с двумя функциями вместе?

Я попытался их объединить, но получил ошибки:

enum Barcode :String {
    case UPCA(Int, Int, Int) = "Order 1" // Enum with raw type cannot have cases with arguments
    case QRCode(String) = "Order 2" // Enum with raw type cannot have cases with arguments
}
4b9b3361

Ответ 1

Да, это возможно. Перечисление может содержать как связанные значения, так и необработанные значения. (Свифт 5 и 4)

Сокращенное обозначение

Проблема с вашим кодом заключается в том, что вы используете сокращенную запись для RawRepresentable и определяете связанные типы.

Давайте посмотрим, как определить их отдельно:

1) RawRepresentable (сокращенная запись):

enum Barcode: String {
    case UPCA   = "order 1"
    case QRCode = "order 2"
}

2) Связанные типы:

enum Barcode {
    case UPCA(Int, Int, Int)
    case QRCode(String)
}

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

Решение

Определите перечисление со связанными значениями, а затем реализуйте соответствие RawRepresentable отдельно в расширении (то есть, не используя сокращенную запись).

Пример:

enum Barcode {
    case UPCA(Int, Int, Int)
    case QRCode(String)
}

extension Barcode: RawRepresentable {

    public typealias RawValue = String

    /// Failable Initalizer
    public init?(rawValue: RawValue) {
        switch rawValue {
        case "Order 1":  self = .UPCA(1,1,1) 
        case "Order 2":  self = .QRCode("foo")
        default:
            return nil
        } 
    }

    /// Backing raw value
    public var rawValue: RawValue {
        switch self {
        case .UPCA:     return "Order 1"
        case .QRCode:   return "Order 2"
        }
    }

}

Незначительная деталь

В этом решении значения по умолчанию для связанных значений, например .UPCA(1,1,1) должны быть предоставлены при построении перечисления из аргумента rawValue. Вы можете придумать и использовать связанные типы как часть необработанного исходного значения - что является более мощным, но добавляет некоторую сложность.

Рекомендации

Для получения дополнительной информации по этой теме см . Превосходное описание Оле Бегеманна.

Ответ 2

Ответы здесь замечательные, но не предоставляют альтернативы, так вот вот один:

Я пытаюсь написать удобную оболочку для API parse.com rest, и, честно говоря, это ограничение, навязанное swift, заставило меня написать немного больше кода, но конечный результат более читабельен:

class Parse {

    enum Endpoint {
        case signUp(ParseHTTPBody)
        case login(ParseHTTPBody)
    }

}

extension Parse.Endpoint {

    var httpMethod: String {
        switch self {
        case .signUp, .login:
            return "POST"
        }
    }

    var path: String {
        switch self {
        case .signUp:
            return "/1/users"
        case .login:
            return "/1/login"
        }
    }
}

Обратите внимание, теперь я httpMethod и path вместо rawValue, что более читаемо в моем случае:

func setParseEndpoint(endpoint: Parse.Endpoint) -> Self {

    URL = NSURL(string: baseURL + endpoint.path)
    HTTPMethod = endpoint.httpMethod

    return self
}

Ответ 3

Начиная с Swift 3 вы можете иметь оба в одном перечислении.


Старый ответ:

Сообщения об ошибках кажутся довольно ясными: вы должны выбрать одно или другое.

Я не знаю, как это работает за кулисами, так что это предположение, но вполне вероятно, что аргументы case хранятся в виде значения кортежа, где в противном случае будет сохранено значение "Raw Type"

Ответ 4

Как уже указывал @Jiaaro, вы не можете этого сделать (в том числе в Beta5).

Однако это будет иметь смысл: перечисление с атрибутами значений может быть реализовано как "дискриминированный союз" или "вариант" (см. также wiki "tagged union" ), где "исходная ценность" будет играть роль "тега".

Это перечисление тогда будет занимать пространство наибольшего размера любого атрибута типа плюс размер тега (плюс дополнение для выравнивания).

Ответ 5

Я решил это так:

enum Barcode {

   case UPCA(Int, Int, Int)// = "Order 1"
   case QRCode(String)// = "Order 2"

   static func customRawValue(rawValue: String) -> Barcode? {

       switch rawValue {

       case "Order 1": return Barcode.UPCA(0, 0, 0)
       case "Order 2": return Barcode.QRCode("")
       default: return nil
       }
    }

    var customRawValue : String {

       switch self {
       case .UPCA: return "Order 1"
       case .QRCode: return "Order 2"
       }
    }
}

if let barcode = Barcode.customRawValue("Order 1") {

   print("Barcode found with custom rawValue: \(barcode)")

   print("Custom rawValue: \(barcode.customRawValue)")
}

Это несколько хакерство, но это решение отлично поработало для моей цели!