转换操作员迅速 [英] Conversion operator in swift

查看:193
本文介绍了转换操作员迅速的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is it possible to write custom conversion (casting) operator in swift? Especially I'm looking for enums conversion, ex:

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

Of course, I can convert to String with explicit method, but I would like to have implicit mechanism.

推荐答案

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

Disclaimer/TL;DR! This answer pertains to the technical question as to whether we can possibly implement implicit bridging mechanisms between different Swift types ourself. The answer is: for some cases, yes, but only in a limited sense and by means of "hacks": do not use this is production code!

正如MartinR在他的评论中写道,自定义转换方法不适用于(本机)Swift。

As MartinR writes in his comment, custom conversion methods are not present for (native) Swift.

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

For the technical discussion we can, however, (ab)use the internal protocol _ObjectiveCBridgeable to allow implicit bridging from your enum to Obj-C objects, in this case e.g. NSString. For a more detailed Q&A of the subject of the internal protocol _ObjectiveCBridgeable, see

  • Is it possible to replicate Swifts automatic numeric value bridging to Foundation (NSNumber) for (U)Int8/16/32/64 types?

之前继续,我将从上面的线索引用免责声明

Before proceeding, I'll quote a disclaimer from my answer in thread above:


...注意 _ObjectiveCBridgeable 是内部/隐藏协议
_UnderScorePreFixedProtocol ),因此基于它的解决方案可能会破坏
在即将到来的Swift版本中没有警告。

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






示例# 1:实现你的枚举的隐含桥接到 NSString

可用的初始化器哟ur enum,允许(尝试)初始化 String 实例:

First lets add a failable initializer to your enum, allowing (attempted) initialization by String instances:

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
        }
    }
}

接下来,让$ code> MyEnum 至 _ObjectiveCBridgeable ,如与上述链接的线程更详细的说明

Next up, let MyEnum conform to _ObjectiveCBridgeable, as described in more detail in the 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

With the conformance above, we can now make use of implicit bridging from MyEnum instances to 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本机类型


Example #2: implementing implicit bridging of your enum to a custom Swift native type

甚至可以进一步滥用 _ObjectiveCBridgeable 协议,使用其(深度后端)机制来实现两种本机Swift类型之间的隐式桥接,限制类型桥接必须是引用类型(具体来说:该类型的实例必须由 AnyObject 表示,因此引用类型限制)。

We may even abuse the _ObjectiveCBridgeable protocol further, using its (deep backend) mechanisms to implement implicit bridging between two native Swift types, with the limitation that the type bridged to must be a reference type (specifically: instances of the type must be representable by AnyObject, hence the reference type limitation).

MyEnum 如上所述,但另外定义一个引用(类)类型 Foo ,并将 MyEnum _ObjectiveCBridgeable 与桥接键入 _ObjectiveCType 设置为 Foo

Let MyEnum be as defined above, but additionally, define a reference (class) type Foo, and conform MyEnum to _ObjectiveCBridgeable with the bridged to type, _ObjectiveCType being set to 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

We can now make use of implicit bridging from MyEnum instances to 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 的唯一类型),否则产生编译时间

Finally note that you may, for any given type (say, MyEnum), naturally only implement implicit bridging to a single other (reference) type; since you can only conform to _ObjectiveCType once (for a unique type for the typealias _ObjectiveCType), otherwise yielding a compile time error for redundant protocol conformance.

以上内容为Swift 2.2进行了测试。

The above is tested for Swift 2.2.

这篇关于转换操作员迅速的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆