swift - swift 中的转换运算符

标签 swift enums type-conversion typecast-operator

是否可以在 swift 中编写自定义转换(转换)运算符?特别是我正在寻找枚举转换,例如:

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,但我希望有隐式机制。

最佳答案

免责声明/TL;DR!这个答案属于技术问题,即我们是否可以自己在不同的 Swift 类型之间实现隐式桥接机制。答案是:在某些情况下,是的,但只是在有限的意义上和通过“黑客”手段:不要使用这是生产代码!

Swift 内部协议(protocol)滥用:我们可能会对 Obj-C 对象实现隐式机制(例如 NSNumberNSString ...)

正如 MartinR 在他的评论中所写,(原生)Swift 不存在自定义转换方法。

但是,对于技术讨论,我们可以(ab)使用内部协议(protocol)_ObjectiveCBridgeable 来允许从您的枚举到Obj-C 对象的隐式桥接,在这种情况下例如NSString。有关内部协议(protocol) _ObjectiveCBridgeable 主题的更详细问答,请参阅

在继续之前,我将引用我在上面线程中的回答中的免责声明:

... note that _ObjectiveCBridgeable is an internal/hidden protocol (_UnderScorePreFixedProtocol), so solutions based on it might break without warning in upcoming Swift versions.


示例 #1:实现枚举到 NSString

的隐式桥接

首先让我们向您的枚举添加一个可失败的初始化程序,允许(尝试)通过 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,如 thread linked to above 中更详细的描述

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 协议(protocol),使用它的(深度后端)机制来实现两个原生 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 一次(对于类型别名 _ObjectiveCType 的唯一类型),否则会产生冗余协议(protocol)一致性的编译时错误。


以上是针对 Swift 2.2 测试的。

关于swift - swift 中的转换运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38477905/

相关文章:

c++ - 在 C++ 中将二进制 Char 数组转换为整数和 double 组

pattern-matching - 由于 Swift 模式匹配中的顺序导致的意外结果

ios - 我不应该在 viewDidLoad 中使用 UIButton 的 addTarget

ios - 如何创建 segue 或新的 View Controller 以显示在不同的 View Controller 上

c - 打印文本而不是 C 枚举中的值

java - 遍历 EnumMap#entrySet

c# - 将字符串格式化为日期时间

swift - PKAddPassButton 根本不显示图标

java - 枚举可以有抽象方法吗?

c - GCC 不在 printf 中进行默认类型转换