我正在尝试构建一个可以使用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执行失败:Untitled Page.xcplaygroundpage:9:17: 错误:无法使用类型为“(T)”的参数列表调用“sin” INIT(X:T){V =的sin(x)}
Untitled Page.xcplaygroundpage:9:17:注意:这些部分匹配的参数列表存在'sin'的重载: (浮动),(双) 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不可知的库,而不会增加很多开销?
答案 0 :(得分:5)
不幸的是,目前在Swift中实现sin()
的方式并不容易。它必须被视为运算符(如Equatable
和==
如何工作),以便您可以将其添加为协议要求。
@matt's solution是一个很好的快速修复,但是如果你想要更永久的东西,你可能需要考虑创建一个协议,然后扩展浮点类型,以便让你重载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}
(随意添加更多数学函数)
我们必须使用阴影&#39;这里计算的属性弥补了我们不能简单地使用sin()
作为协议要求的事实。它并不理想 - 但可能和你一样好。
您现在可以继续使用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
答案 1 :(得分:0)
可以尝试这样的事情:
struct MyStruct<T:FloatingPointType> {
var v:T
init(x:T){
switch x {
case is Float:
v = sin(x as! Float) as! T
case is Double:
v = sin(x as! Double) as! T
case is CGFloat:
v = sin(x as! CGFloat) as! T
default:v = 0.0 as! T
}
}
}
似乎工作:
let s = MyStruct(x:Float(3))
s.v // 0.14112
let s2 = MyStruct(x:Double(3))
s2.v // 0.1411200080598672
let s3 = MyStruct(x:CGFloat(3))
s3.v // 0.1411200080598672