簡體   English   中英

Swift,數學函數和協議

[英]Swift, math functions and 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
}

我得到“找不到接受提供的參數的罪的重載”

然后我嘗試使用MathemticType試圖模仿我已經為+運算符所做的事情

(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
}

它按預期工作。

所以這個問題可能會成為“我如何將其概括為Double和Float”?

編譯器錯誤是因為您將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)
    }
}

你的MathematicType協議,以及你在FloatDouble擴展中對它的一致性聲明,說FloatDouble應該提供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可用作泛型參數,意思是“你可以采用正弦的類型”,你需要一個通用的sin函數。 像這樣的東西(快速kludgy解決方案,可能更好):

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")
}

(另請注意,已經存在FloatDouble符合的協議,因此我在示例中使用了該協議。)

我認為問題是運算符要求和實例方法要求是不同的,即使它們在語法上看起來相似。 運營商始終在全球范圍內定義,因此運營商要求是全球運營商的要求。 另一方面,實例方法要求是實例方法的要求。 無法指定全局功能要求。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM