Оператор преобразования в swift

Можно ли написать собственный оператор преобразования (приведения) вswift? Особенно я ищу преобразования enums, например:

enum MyEnum : Int {
    case Case1 = 0
    case Case2
    func __conversion() -> String { // doesn't work since Swift 1.0
        switch self {
        case Case1: return "Case 1"
        case Case2: return "Case 2"
        }
    }
}

let enumStr: String = MyEnum.Case1

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

 Feldur20 июл. 2016 г., 13:02
Разве он не может сделать перечисление строковым типом и использовать rawValue?
 dfri20 июл. 2016 г., 13:08
@Feldur Я считаю, что источник этого вопроса не в том, как изменить конкретныеrawValue тип данного перечисления, а скорее потенциальное преобразование (в идеале, для OP: неявное) в другие заданные типы (которые не совпадают с типомrawValue).
 brigadir20 июл. 2016 г., 12:04
@MartinR, как насчетString инициализатор сMyEnum входной параметр?
 Martin R20 июл. 2016 г., 11:54
Нет, пользовательские методы конвертации были удалены из Swift давно.

Ответы на вопрос(1)

Решение Вопроса

DR! Этот ответ относится к техническому вопросу о том,мы можем возможно самостоятельно реализуем механизмы неявного связывания между различными типами Swift. Ответ таков: в некоторых случаях да, но только в ограниченном смысле и с помощью «хаков»: не используйте это рабочий код!

Быстрое злоупотребление внутренним протоколом: мы можем реализовать неявные механизмы для объектов Obj-C (например,NSNumber, NSString ...)

Как пишет MartinR в своем комментарии, пользовательские методы преобразования отсутствуют для (родного) Swift.

Длятехническое обсуждение мы можем, однако, (ab) использовать внутренний протокол_ObjectiveCBridgeable чтобы разрешить неявное связывание от вашего enum к объектам Obj-C, в этом случае, например,NSString, Для более подробной информации о внутреннем протоколе_ObjectiveCBridgeable, увидеть

Можно ли реплицировать автоматическое связывание числовых значений Swifts в Foundation (NSNumber) для типов (U) Int8 / 16/32/64?

Прежде чем продолжить, я процитируюотказ из моего ответа в ветке выше:

... Обратите внимание, что_ObjectiveCBridgeable это внутренний / скрытый протокол (_UnderScorePreFixedProtocol), поэтому решения на его основе могут без предупреждения сломаться в следующих версиях Swift.

Пример # 1: реализация неявного соединения вашего перечисления сNSString

Во-первых, давайте добавим в ваш enum перечисляемый инициализатор, что позволит (попытаться)String экземпляры:

import Foundation

enum MyEnum: Int {
    case Case1 = 0
    case Case2

    init?(string: String) {
        switch string {
        case "Case 1": self = .Case1
        case "Case 2": self = .Case2
        default: return nil
        }
    }
}

Далее пустьMyEnum соответствовать_ObjectiveCBridgeableкак описано более подробно внить связана с выше

extension MyEnum: _ObjectiveCBridgeable {

    typealias _ObjectiveCType = NSString

    static func _isBridgedToObjectiveC() -> Bool {
        return true
    }

    static func _getObjectiveCType() -> Any.Type {
        return _ObjectiveCType.self
    }

    func _bridgeToObjectiveC() -> _ObjectiveCType {
        return NSString(string: "Case \(self.rawValue+1)")
    }

    static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) {
        result = MyEnum(string: source as String)
    }

    static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) -> Bool {
        self._forceBridgeFromObjectiveC(source, result: &result)
        return true
    }
}

Учитывая приведенное выше соответствие, теперь мы можем использовать неявные мосты изMyEnum случаи кNSString

/* example usage */
var myCase: MyEnum = .Case1
var enumNSstr: NSString = myCase // MyEnum -> NSString, implicit

print(enumNSstr) // Case 1

enumNSstr = "Case 2"

// NSString -> MyEnum, by type conversion (castable)
myCase = (enumNSstr as MyEnum) ?? .Case1
print(myCase) // Case 2

Пример №2: реализация неявного соединения вашего перечисления с собственным нативным типом Swift

Мы можем даже злоупотреблять_ObjectiveCBridgeable далее протокол, используя его механизмы (глубокий бэкэнд) для реализации неявного моста между двумя нативными типами Swift, с ограничением на тип мостав должен быть ссылочным типом (в частности: экземпляры типа должны быть представленыAnyObjectотсюда ограничение ссылочного типа).

ПозволятьMyEnum быть таким, как определено выше, но дополнительно, определить тип ссылки (класса)Fooи соответствоватьMyEnum в_ObjectiveCBridgeable с мостомпечатать, _ObjectiveCType устанавливается наFoo.

class Foo {
    var bar: String
    init(bar: String) { self.bar = bar }
}

extension MyEnum: _ObjectiveCBridgeable {

    typealias _ObjectiveCType = Foo

    static func _isBridgedToObjectiveC() -> Bool {
        return true
    }

    static func _getObjectiveCType() -> Any.Type {
        return _ObjectiveCType.self
    }

    func _bridgeToObjectiveC() -> _ObjectiveCType {
        return Foo(bar: "Case \(self.rawValue+1)")
    }

    static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) {
        result = MyEnum(string: source.bar)
    }

    static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) -> Bool {
        self._forceBridgeFromObjectiveC(source, result: &result)
        return true
    }
}

Теперь мы можем использовать неявные мосты изMyEnum случаи кFoo

/* example usage */
var myCase: MyEnum = .Case1
var myFoo: Foo = myCase // MyEnum -> Foo, implicit
print(myFoo.bar) // Case 1

myFoo.bar = "Case 2"

// Foo -> MyEnum, by type conversion (castable)
myCase = (myFoo as? MyEnum) ?? .Case1
print(myCase) // Case 2

Наконец, обратите внимание, что вы можете, для любого данного типа (скажем,MyEnum), естественно, реализуют неявные мосты только с одним другим (ссылочным) типом; так как вы можете соответствовать только_ObjectiveCType один раз (для уникального типа для typealias_ObjectiveCType), в противном случае выдается ошибка времени компиляции для избыточного соответствия протокола.

Выше проверено на Swift 2.2.

 brigadir22 июл. 2016 г., 11:39
спасибо за столь подробное объяснение. Грустно, что это хакерский подход, но все равно очень полезно.
 dfri22 июл. 2016 г., 15:54
@brigadir рад углубиться в эту тему! Но опять же, как вы также пишете, это хаки, и их не стоит использовать на практике, даже если с ними интересно играть :)

Ваш ответ на вопрос