Swift,数学函数和协议

时间:2014-08-25 13:42:00

标签: function math swift protocols

我试图创建2个协议ArithmeticType和MathematicType,它们将用于泛型运算符函数的where子句

protocol ArithmeticType {
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
}

extension Int : ArithmeticType {
}

extension Double : ArithmeticType {
}

extension Float : ArithmeticType {
}

ArithmeticType按预期工作,Int,Float和Double符合它。但是以下失败

import Darwin

protocol MathematicType {
    func sin(x: Self) -> Self
}

extension Double : MathematicType {
}

extension Float : MathematicType {
}

在我读到的游乐场的控制台输出上:

Playground execution failed: <EXPR>:35:1: error: type 'Double' does not conform to protocol 'MathematicType'
extension Double : MathematicType {
^
<EXPR>:32:10: note: protocol requires function 'sin' with type 'Double -> Self'
    func sin(x: Self) -> Self
         ^
<EXPR>:39:1: error: type 'Float' does not conform to protocol 'MathematicType'
extension Float : MathematicType {
^
<EXPR>:32:10: note: protocol requires function 'sin' with type 'Float -> Self'
    func sin(x: Self) -> Self
         ^

我希望数学函数的行为与上面的运算符相似。有什么办法吗?

==编辑:

现在我意识到试图简化我的问题是一个坏主意。上下文是这个类(可选值的向量)

class Vector<T> {

    var data=[T?]()

    init(fromArray: Array<T>) {
        for i in fromArray {
            data.append(i)
        }
    }

    init() {
    }

    init(count: Int){
        for i in 0..<count {
            data.append(nil)
        }
    }

    init(count: Int, repeatedValue: T) {
        for i in 0..<count {
            data.append(repeatedValue)
        }
    }

    func count() -> Int {
        return data.count
    }

    func append(newElement: T?) {
        data.append(newElement)
    }

    subscript(index: Int) -> T? {
        let i = index>0 ? index % count() : -index % count()
        return data[i]
    }
}

在它之外我为+运算符

定义了一个泛型函数
func +<T where T: ArithmeticType>(left: Vector<T>, right: Vector<T>) -> Vector<T> {
    let resultCount = max(left.count(),right.count())
    var result = Vector<T>()
    for i in 0..<resultCount {
        if left[i] != nil && right[i] != nil {
            result.append(left[i]!+right[i]!)
        }
        else {
            result.append(nil)
        }
    }
    return result
}

按预期工作,但是当我尝试将通用sin函数定义为

func sin<T where T : FloatingPointType>(x: Vector<T>) -> Vector<T>{
    var result = Vector<T>()
    for i in 0..<x.count() {
        if let o = x[i] {
            result.append(sin(o))
        }
        else {
            result.append(nil)
        }
    }
    return result
}

我得到了#34;无法找到接受所提供的参数的罪过重&#34;

然后我尝试用MathemticType试图模仿我已经为+ operator

做的事情

(ArithmeticType的灵感来自IntegerAritmeticType源,通过命令点击导入swift,而不是我对我所做的事情的了解)

==更新

如果我只为Double

编写专门的函数
func sin(x: Vector<Double>) -> Vector<Double>{
    var result = Vector<Double>()
    for i in 0..<x.count() {
        if let o = x[i] {
            result.append(Darwin.sin(o))
        }
        else {
            result.append(nil)
        }
    }
    return result
}

它按预期工作。

所以问题可能会成为&#34;我怎样才能将其概括为Double和Float&#34; ?

3 个答案:

答案 0 :(得分:2)

编译器错误是因为您将sin()声明为MathematicType协议的方法,然后声明Double实现了MathematicType,但实际上并未编写sin()方法。

extension Double {
    func sin(x: Double) -> Double {
        return Darwin.sin(x)
    }
}

我认为这不是你想要的,不是吗?你希望能够写下这个:

let myAngle = 3.14159
let sineValue = myAngle.sin()

如果是这种情况,您的协议和扩展名应如下所示:

protocol MathematicType {
    func sin() -> Self
}

extension Double : MathematicType {
    func sin() -> Double {
        return Darwin.sin(self)
    }
}

答案 1 :(得分:2)

您的MathematicType协议以及您在FloatDouble扩展程序中对其的一致声明,请FloatDouble提供{{1}作为实例方法。也就是说,你说应该能够编写如下代码:

sin

请注意,let zero = 0.0 // inferred type Double zero.sin(1.5707963268) // returns about 1.0 的调用实际上并不与sin的值相关,因此这可能不是您想要的行为。

你可能希望zero成为一个自由函数,所以你可以写:

sin

右?

在这种情况下,您的工作已经完成......标准库定义了两者:

sin(1.5707963268)

如果你真正想要的是func sin(x: Double) -> Double func sin(x: Float) -> Float 可用作通用参数,意思是“你可以采用正弦的类型”,你需要一个通用的MathematicType函数。像这样的东西(快速kludgy解决方案,可能更好):

sin

(另请注意,已经存在func sine<T: FloatingPointType>(x: T) -> T { if let v = x as? Double { return sin(v) as T } if let v = x as? Float { return sin(v) as T } fatalError("unknown FloatingPointType") } Float符合的协议,因此我在示例中使用了该协议。)

答案 2 :(得分:1)

我认为问题是运算符要求和实例方法要求是不同的,即使它们在语法上看起来相似。运营商始终在全球范围内定义,因此运营商要求是全球运营商的要求。另一方面,实例方法要求是实例方法的要求。无法指定全局功能要求。