Luk*_*ela 5 generics type-conversion swift
我有一个通过泛型 T 类型接受数字类型的类,我希望能够将其转换为 ,CGFloat但它抛出:
无法使用类型为“(T)”的参数列表调用类型“CGFloat”的初始化程序
我必须在课堂上做什么才能成功转换它?
CGFloat(self.top) - 这就是它不喜欢的
'T' 类型定义如下:
protocol Numeric:Comparable, Equatable {
//
init(_ v:Float)
init(_ v:Double)
init(_ v:Int)
init(_ v:UInt)
init(_ v:Int8)
init(_ v:UInt8)
init(_ v:Int16)
init(_ v:UInt16)
init(_ v:Int32)
init(_ v:UInt32)
init(_ v:Int64)
init(_ v:UInt64)
}
extension Float: Numeric {}
extension Double: Numeric {}
extension Int: Numeric {}
extension Int8: Numeric {}
extension Int16: Numeric {}
extension Int32: Numeric {}
extension Int64: Numeric {}
extension UInt: Numeric {}
extension UInt8: Numeric {}
extension UInt16: Numeric {}
extension UInt32: Numeric {}
extension UInt64: Numeric {}
class MyClass<T: Numeric> {
//...
var top:T
}
Run Code Online (Sandbox Code Playgroud)
当我尝试使用as然后这个运行时错误弹出
无法将“Swift.Double”(0x1002b64f8)类型的值转换为“CoreGraphics.CGFloat”(0x1004e8740)。
作为我在这里答案的扩展,您可以通过使用“影子方法”静态地实现此目的,以便允许Numeric类型将自身强制为任何其他Numeric类型(假设目标类型的初始化程序被列为协议要求) 。
例如,您可以Numeric像这样定义您的协议:
protocol Numeric : Comparable, Equatable {\n\n init(_ v:Float)\n init(_ v:Double)\n init(_ v:Int)\n init(_ v:UInt)\n init(_ v:Int8)\n init(_ v:UInt8)\n init(_ v:Int16)\n init(_ v:UInt16)\n init(_ v:Int32)\n init(_ v:UInt32)\n init(_ v:Int64)\n init(_ v:UInt64)\n init(_ v:CGFloat)\n\n // \'shadow method\' that allows instances of Numeric\n // to coerce themselves to another Numeric type\n func _asOther<T:Numeric>() -> T\n}\n\nextension Numeric {\n\n // Default implementation of init(fromNumeric:) simply gets the inputted value\n // to coerce itself to the same type as the initialiser is called on\n // (the generic parameter T in _asOther() is inferred to be the same type as self)\n init<T:Numeric>(fromNumeric numeric: T) { self = numeric._asOther() }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n然后使类型符合Numeric如下所示:
// Implementations of _asOther() \xe2\x80\x93 they simply call the given initialisers listed\n// in the protocol requirement (it\'s required for them to be repeated like this,\n// as the compiler won\'t know which initialiser you\'re referring to otherwise)\nextension Float : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nextension Double : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nextension CGFloat : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nextension Int : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nextension Int8 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nextension Int16 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nextension Int32 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nextension Int64 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nextension UInt : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nextension UInt8 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nextension UInt16 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nextension UInt32 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nextension UInt64 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}\nRun Code Online (Sandbox Code Playgroud)\n\n用法示例:
\n\nclass MyClass<T : Numeric> {\n\n var top : T\n\n init(_ top:T) {\n self.top = top\n }\n\n func topAsCGFloat() -> CGFloat {\n return CGFloat(fromNumeric: top)\n }\n}\n\nlet m = MyClass(Int32(42))\nlet converted = m.topAsCGFloat()\n\nprint(type(of:converted), converted) // prints: CGFloat 42.0\nRun Code Online (Sandbox Code Playgroud)\n\n这个解决方案可能不比实现一个切换符合Numeric\xe2\x80\x93 的每种类型的方法短,但是由于这个解决方案不依赖于运行时类型转换,编译器可能有更多的优化机会。
它还受益于静态类型检查,这意味着您无法Numeric在不实现将该类型转换为另一种类型的逻辑的情况下符合新类型Numeric(在您的情况下,如果该类型未在这switch)。
此外,由于封装,扩展起来更加灵活,因为转换类型的逻辑是在符合 的每个单独的具体类型中完成的Numeric,而不是在处理可能情况的单个方法中完成的。
| 归档时间: |
|
| 查看次数: |
1610 次 |
| 最近记录: |