swift – 如何通过常用的初始化程序在相关类型之间进行转换?

swift – 如何通过常用的初始化程序在相关类型之间进行转换?,第1张

概述我正在尝试构建一系列可以互相转换的类型.例如,Float和Double可以通过其初始化器相互转换.我不想创建一个详尽的初始化列表,显示每种类型都可以转换为每种其他类型. 我试图在Playground中做这样的事情,但它崩溃了: protocol FloatConvertible { init(_ x:FloatConvertible)}extension FloatConvertib 我正在尝试构建一系列可以互相转换的类型.例如,float和Double可以通过其初始化器相互转换.我不想创建一个详尽的初始化列表,显示每种类型都可以转换为每种其他类型.

我试图在Playground中做这样的事情,但它崩溃了:

protocol floatConvertible {    init(_ x:floatConvertible)}extension floatConvertible {    init(_ x:floatConvertible){self.init(Self(x))}}extension float:floatConvertible {}extension Double:floatConvertible {}func transmute<T:floatConvertible,U:floatConvertible>    (a:T,b:U) -> T {    return T(b)}transmute(float(3.1),b: Double(2.6))

我最终的目标不仅仅是进行转换,而是将a乘以b,如下所示:

func *<T:floatConvertible,U:floatConvertible> (a:T,b:U) -> T{    return a * T(b)}

这样我就可以表达倍增.

有没有办法做到这一点?我认为部分问题是看起来像Double(Double(Double(Double(…)))的结构,但我不认为我可以设置一个确保T!= U的约束.

问题是在你的init(_ x:floatConvertible)中,Swift无法推断x的具体类型是什么.它只知道它是一个floatConvertible.因此,当您尝试执行Self(x)时,虽然它可以推断Self的具体类型,但它不知道您要调用哪个初始化器,这意味着它将默认为您的init(_ x:floatConvertible)初始化器,因此创造一个无限循环.

如果您为自定义初始化程序提供参数名称,您将看到Swift抱怨它无法找到正确的初始化程序:

protocol floatConvertible {    init(c x:floatConvertible)}extension floatConvertible {    init(c x:floatConvertible) {        // error: missing argument name 'c:' in call        // (i.e it can't find the concrete type's initialiser)        self.init(Self(x))     }}

因此,一种可能的解决方案是通过切换x可能的具体类型在运行时解决此问题.然而,这并不像静态解决这个问题那么好,因为您可以从提高安全性和在某些情况下提高性能中受益.

为了静态地执行此 *** 作,您可以在协议中添加一个通用的_asOther’shadow’函数,该函数可以将给定的浮点类型转换为另一个浮点类型,以及将具体类型的初始化函数添加到协议要求中.

这样您就不必列出所有可能的转换组合 – 您现在只需从初始化程序中调用_asOther即可.

protocol floatConvertible {    init(_ other:float)    init(_ other:Double)    init(_ other:CGfloat)    init(fromOther x:floatConvertible)    func _asOther<T:floatConvertible>() -> T}extension floatConvertible {    init(fromOther x:floatConvertible) {self = x._asOther()}}// note that we have to implement these for each extension,// so that Swift uses the concrete types of self,preventing an infinite loopextension float : floatConvertible {    func _asOther<T:floatConvertible>() -> T {return T(self)}}extension Double : floatConvertible {    func _asOther<T:floatConvertible>() -> T {return T(self)}}extension CGfloat : floatConvertible {    func _asOther<T:floatConvertible>() -> T {return T(self)}    // note that CGfloat doesn't implement its own initialiser for this,// so we have to implement it ourselves    init(_ other:CGfloat) {self = other}}func transmute<T:floatConvertible,U:floatConvertible>(value: T,to: U.Type) -> U {    return U(fromOther: value)}let f = transmute(value: CGfloat(2.6),to: float.self)print(type(of: f),f) // prints: Double 2.59999990463257

在初始化器中,将在输入值上调用_asOther,并为通用参数T推断self的类型(在此上下文中,self保证是具体类型).然后将在x上调用_asOther函数,该函数将返回作为给定目标类型的值.

请注意,您不必为自定义初始化程序使用fromOther:参数标签 – 这仍然可以在没有任何标签的情况下使用.虽然我强烈建议在编译时使用它来捕获代码的任何问题(Swift会接受在运行时会导致无限循环的代码).

另外作为旁注,您应该重新考虑您的设计,以了解您的*过载如何工作.返回你输入的更精确的类型(即float * Double = Double)会更有意义 – 否则你就会不必要地失去精确度.

总结

以上是内存溢出为你收集整理的swift – 如何通过常用的初始化程序在相关类型之间进行转换?全部内容,希望文章能够帮你解决swift – 如何通过常用的初始化程序在相关类型之间进行转换?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1050319.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存