2016-07-06 27 views
2

我定義了一個簡單的通用結構 - 它的唯一要求是,它的存儲性能是Comparable提供專門的初始化一個通用的結構

struct Bounds<A: Comparable> { 
    let lower: A 
    let upper: A 
} 

不過,我想提供一對夫婦專門用於初始化該結構將使用一些數學運算來設置屬性。

init(value: Double, tolerance: Percentage) { 
     self.lower = value * (1 - tolerance) 
     self.upper = value * (1 + tolerance) 
    } 

    init(value: Measurement, tolerance: Percentage) { 
     self.lower = value.value * (1 - tolerance) 
     self.lower = value.value * (1 - tolerance) 
    } 

結果應該明顯是兩個不同的結構,其中A是一個DoubleMeasurement

但我該怎麼做?

我無法在定義中提供專門的init方法,因爲編譯器會抱怨Double is not convertible to A。 OK ......

我不能提供的特定類型(where A == Double),因爲編譯器限制單個擴展在init方法抱怨:

相同類型的要求使得泛型參數「A」非通用

也許我應該使用哪個都DoubleMeasurement符合在初始化的協議,但是這似乎很奇怪,因爲Bounds結構應該只關心它們都符合Comparable

我覺得我要麼錯過了一些非常簡單的事情,要麼嘗試着去做一些真正被泛型所誤導的東西。這是什麼,所以?

+0

如何定義「百分比」和「測量」? –

回答

1

你問不完全的東西,但一個可能的解決方法(SWIFT 3):

extension Bounds where A: FloatingPoint { 
    init(value: A, tolerance: A) { 
     self.lower = value * (A(1) - tolerance) 
     self.upper = value * (A(1) + tolerance) 
    } 
} 

let b = Bounds(value: 4.0, tolerance: 0.1) 
print(b.dynamicType) // Bounds<Double> 
0

你可以限制爲例如改變你的通用更強烈,訪問協議blueprinted方法一個Double值的通用類型。

protocol FromDoubleTransformable { 
    static func doubleToSelf(from: Double) -> Self 
} 

/* drawback: only types conforming to 'FromDoubleTransformable' 
    will be able to be used as generic in 'Bounds' below   */ 
extension Int: FromDoubleTransformable { 
    static func doubleToSelf(from: Double) -> Int { 
     // simple example without any out-of-bounds checking 
     return Int(from) 
    } 
} 

struct Bounds<A: protocol<Comparable, FromDoubleTransformable>> { 
    let lower: A 
    let upper: A 

    init(value: Double, tolerance: Double) { 
     self.lower = A.doubleToSelf(value * (1 - tolerance)) 
     self.upper = A.doubleToSelf(value * (1 + tolerance)) 
    } 
} 

let foo = Bounds<Int>(value: 120, tolerance: 0.1) 
print(foo.dynamicType)  // Bounds<Int> 
print(foo.lower, foo.upper) // 108 132 
0

主要問題是您正在對尚未定義操作的類型執行操作。

E.g.

value * (1 - tolerance) 

被定義,其中的操作與Int之間Tolerance-

這是你如何修復它

protocol BoundsType: Comparable { 
    func *(lhs: Self, rhs: Self) -> Self 
    var prev: Self { get } 
    var next: Self { get } 
    init(double: Double) 
    init<M:Measurement>(measurement:M) 
} 

protocol Percentage { 
    associatedtype BoundsType 
    var toBoundsType: BoundsType { get } 
} 
protocol Measurement { 
    associatedtype BoundsType 
    var toBoundsType: BoundsType { get } 
} 

struct Bounds<A: BoundsType, P:Percentage, M:Measurement 
       where P.BoundsType == A, M.BoundsType == A> { 
    let lower: A 
    let upper: A 

    init(value: Double, tolerance: P) { 
     self.lower = A(double:value) * (tolerance.toBoundsType.prev) 
     self.upper = A(double:value) * (tolerance.toBoundsType.next) 
    } 

    init(value: M, tolerance: P) { 
     self.lower = A(measurement:value) * tolerance.toBoundsType.prev 
     self.upper = A(measurement:value) * tolerance.toBoundsType.next 
    } 
} 
0

的正確答案,這是馬丁R.的「解決辦法。」這裏的問題是,Comparable沒有定義任何這些數學運算,甚至沒有保證它是數字類型。它可以很容易地是一個字符串,或一個數組,或實現Comparable的任何其他類型。

所以,是的,您必須編寫擴展,限制爲實現這些運算符的通用協議或所討論的具體類型。例如:

extension Bounds where A: FloatingPoint { 
    init(value: A, tolerance: Percentage) { 
     self.lower = value * (1 - tolerance) 
     self.upper = value * (1 + tolerance) 
    } 
} 

或者,如果Measurement不符合FloatingPoint

extension Bounds where A == Measurement { 
    init(value: A, tolerance: Percentage) { 
     self.lower = value.value * (1 - tolerance) 
     self.upper = value.value * (1 + tolerance) 
    } 
} 

而且,因爲你可能不希望使用任何非數字類型的界限,那麼我會定義它沿着這些線:

struct Bounds<A: Numeric & Comparable> { 
    let upper: A 
    let lower: A 
}