使Swift泛型使用重载函数

时间:2016-05-22 01:24:58

标签: swift generics

我正在尝试构建一个可以使用MyStruct<T>Float进行内部存储的通用类型Double。在初始化程序中,我传递了一个类型为T的参数(我打算将其作为FloatDouble)。该初始化程序会调用某些触发函数,例如sin()cos()。这两个函数都在系统库中重载,以提供FloatDouble版本。

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不可知的库,而不会增加很多开销?

2 个答案:

答案 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