我正在尝试构建通用类型 MyStruct<T>
可以使用 Float
或 Double
用于内部存储。在初始化程序中,我传递了一个 T 类型的参数(我打算将其设为 Float
或 Double
)。该初始化程序调用一些三角函数,例如 sin()
和 cos()
.这两个函数都在系统库中重载以提供 Float
和 Double
版本。
var f:Float=1.2
var d:Double=1.2
sin(f) //0.9320391
sin(d) //0.9320390859672263
问题是,我不能在我的通用结构中使用它们。一个精简的案例看起来像这样:
struct MyStruct<T> {
var v:T
init(x:T){v=sin(x)}
}
因为:
Playground execution failed: Untitled Page.xcplaygroundpage:9:17: error: cannot invoke 'sin' with an argument list of type '(T)' init(x:T){v=sin(x)}
Untitled Page.xcplaygroundpage:9:17: note: overloads for 'sin' exist with these partially matching parameter lists: (Float), (Double) init(x:T){v=sin(x)}
似乎应该有办法让它工作,但感觉很像 this situation .评论表明没有办法要求存在全局函数。
我可以通过使用如下构造来强制这种情况:
init(x:T){v=T(sin(Double(x)))}
并对 T 施加约束,使其可以从 Double
构建, 但这似乎违背了制作 Float
的目的结构的版本,这是为了在代码的关键循环中使用时减少计算工作量。
如果 sin()
感觉这会更容易已在库中定义为通用函数而不是重载函数:
func sin<T:FloatingPointType> (x:T) -> T
但事实就是如此。
有没有一种方法可以让我在标准库之上构建一个与 Float/Double 无关的库,而不会增加很多开销?
最佳答案
不幸的是,没有像目前在 Swift 中实现的 sin()
那样简单的方法来做到这一点。必须将其视为运算符(例如 Equatable
和 ==
的工作方式),以便您可以将其添加为协议(protocol)要求。
@matt's solution是一个很好的快速修复,但如果你想要更永久的东西,你可能需要考虑创建一个协议(protocol),然后扩展浮点类型,以便允许你重载 sin()
函数通用版本。
protocol FloatingPointMathType : FloatingPointType {
var _sinValue : Self { get }
}
extension Float : FloatingPointMathType {
var _sinValue : Float {return sin(self)}
}
extension Double : FloatingPointMathType {
var _sinValue : Double {return sin(self)}
}
extension CGFloat : FloatingPointMathType {
var _sinValue : CGFloat {return sin(self)}
}
func sin<T:FloatingPointMathType>(x:T) -> T {return x._sinValue}
(欢迎添加更多数学函数)
我们必须在这里使用“影子”计算属性来弥补我们不能简单地使用 sin()
作为协议(protocol)要求的事实。这并不理想,但可能与您将要获得的一样好。
您现在可以继续将 sin()
用作通用函数:
struct MyStruct<T:FloatingPointMathType> {
var v : T
init(x:T) {
v = sin(x)
}
}
print(MyStruct(x: Float(3.0)).v) // 0.14112
print(MyStruct(x: Double(3.0)).v) // 0.141120008059867
print(MyStruct(x: CGFloat(3.0)).v) // 0.141120008059867
关于swift - 让 Swift 泛型玩转重载函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37369649/