Swift泛型运算符

时间:2014-09-21 21:46:53

标签: generics swift operator-overloading

我写了一个类似这样的课:

struct Size {
    var width:Double=0
    var height:Double=0
    init(width:Double=0,height:Double=0)
    {
        self.width=width
        self.height=height
    }
    [...]
}

现在我希望能够将一个大小划分为一定数量,我想使用泛型来获得每个可转换为Double的类型的函数。例如 Int CGFloat Float

但是当我插入函数时:

func /<T>(lhs:Size,rhs:T)->Size
{
    return Size(width:lhs.width/Double(rhs),height:lhs.height/Double(rhs))
}

我收到错误

error: cannot invoke 'init' with an argument list of type '(width: Double, height: Double)'
        return Size(width:Double(lhs.width/rhs),height:Double(lhs.height/rhs))
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

这真的很奇怪,因为传递的列表是在类中定义的确切类型(Double)..

如果我以这种方式重写它:

func /<T>(lhs:Size,rhs:T)->Size
{
    let drhs=Double(rhs)
    return Size(width:lhs.width/drhs,height:lhs.height/drhs)
}

然后我收到错误:

error: cannot invoke 'init' with an argument of type 'T'
    let drhs=Double(rhs)
             ^~~~~~~~~~~

甚至更奇怪,因为Swift库文件有很多用于Double,Int或Float类型的初始化器:

extension Double {
    init(_ v: UInt8)
    init(_ v: Int8)
    init(_ v: UInt16)
    init(_ v: Int16)
    init(_ v: UInt32)
    init(_ v: Int32)
    init(_ v: UInt64)
    init(_ v: Int64)
    init(_ v: UInt)
    init(_ v: Int)
}

extension Double {
    init(_ v: Float)
    init(_ v: Float80)
}

我的代码有什么问题?

2 个答案:

答案 0 :(得分:4)

在swift中,泛型需要通过协议约束来完成类型安全。这比使用泛型无法承担安全性的C ++要好得多。通常,您可以使用标准库中的协议来实现这些泛型,但遗憾的是,在您的情况下,您需要定义一个特殊协议并扩展您希望能够使用的所有类型。我已经为Int和Float完成了它,但你可以对你想要使用的所有类型做同样的事情。

protocol DoubleConvertible
{
    func toDouble() -> Double
}
extension Int : DoubleConvertible
{
    func toDouble() -> Double
    {
        return Double(self)
    }
}
extension Float: DoubleConvertible
{
    func toDouble() -> Double
    {
        return Double(self)
    }
}
func /<T : DoubleConvertible>(lhs: Size, rhs: T) -> Size
{
    return Size(width: lhs.width / rhs.toDouble(), height: lhs.height / rhs.toDouble())
}

您必须手动执行此操作的原因是因为没有一个标准库协议(我知道)定义了一个要求,以便可以将数字转换为Double。

答案 1 :(得分:2)

这里的问题是rhs是泛型类型,您不能将double除以泛型类型。 这样的事情有效:

func / (lhs:Size,rhs:Double)->Size
{
    return Size(width: lhs.width/rhs, height:lhs.height/rhs)
}