是否可以在 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 对象实现隐式机制(例如 NSNumber
、NSString
...)
正如 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/