转换操作员迅速 [英] Conversion operator in swift
问题描述
是否可以在 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屋!