2016-01-24 40 views
0

以下是我有:斯威夫特:如何使這個功能一般

class func truncateTailsOfRange(range: Range<Int>, portion: Double) -> Range<Int> { 
    let start = range.startIndex + Int(portion * Double(range.count)) 
    let end = range.endIndex - Int(portion * Double(range.count)) 
    return Range(start: start, end: end) 
} 

我想使這個通用的IntegerType:

class func truncateTailsOfRange<T: IntegerType>(range: Range<T>, portion: Double) -> Range<T> { 
    let start = range.startIndex + T(portion * Double(range.count)) 
    let end = range.endIndex - T(portion * Double(range.count)) 
    return Range(start: start, end: end) 
} 

但我得到的錯誤是:

無法用類型參數列表(T.Distance

012調用類型爲 Double的初始值設定項

這可能嗎?

+0

你需要一個範圍內的所有整數類型?爲每一個你需要的方法創建一個方法會容易得多。 –

+0

我只需要Int,但動機很簡單,沒有理由將其限制爲整數 –

+0

您試圖調用T上的構造函數,但T不是實際的類/結構體/枚舉,而只是一個「類型「。 – davecom

回答

0

首先你需要一個CustomDoubleConvertible協議。這反映了CustomStringConvertible。您將所有可以轉換爲Double的類型擴展。類似於description,它返回Type的String表示。

protocol CustomDoubleConvertible { 

    var doubleValue : Double { get } 
} 

extension Int : CustomDoubleConvertible { 

    var doubleValue : Double { return Double(self) } 

} 

extension Int16 : CustomDoubleConvertible { 

    var doubleValue : Double { return Double(self) } 

} 

如果使功能的擴展,Range本身,你可以利用它的一般本性和它的typealiases

extension Range where Element.Distance : CustomDoubleConvertible { 

現在你可以計算指標的補償,像這樣:

let startOffset = Int(portion * self.count.doubleValue) 
let endOffset = Int(portion * self.count.doubleValue) 

如果進一步限制Range,以便它Element必須是一個BidirectionalIndexType可以使用successorpredecessor

extension Range where Element.Distance : CustomDoubleConvertible, Element : BidirectionalIndexType { 

這可以讓你通過循環偏移,並呼籲successorpredecessor得到完整的功能。

extension Range where Element.Distance : CustomDoubleConvertible, Element : BidirectionalIndexType { 

    func truncateTailsOfRange(portion: Double) -> Range<Element> { 

     let startOffset = Int(portion * self.count.doubleValue) 
     let endOffset = Int(portion * self.count.doubleValue) 

     var start = self.startIndex 
     var end = self.endIndex 

     for _ in 0..<startOffset { start = start.successor() } 
     for _ in 0..<endOffset { end = end.predecessor() } 

     return Range(start: start, end: end) 
    } 
} 

一些測試:

let rangeA = 1...4 // 1..<5 

let rangeB = "a"..."g" 

rangeA.truncateTailsOfRange(0.3) // 2..<4 

rangeB.truncateTailsOfRange(0.3) // has no member .... 



let w : Int16 = 3 
let z : Int16 = 9 

let rangeC = w...z // 3..<10 
rangeC.truncateTailsOfRange(0.4) // 5..<8 
0

這是一個有趣的,但學術活動。

這裏是不是很有效的方法,但可以使用所有範圍類型的工作:

func truncateTailsOfRange<T>(var range: Range<T>, portion: Double) -> Range<T> 
{ 
    let elementCount = Array(range).count 
    let truncationCount = Int(portion * Double(elementCount)) 
    let remainingCount = max(0, elementCount - 2 * truncationCount) 

    for _ in 0..<truncationCount 
    { range.startIndex = range.startIndex.successor() } 

    range.endIndex = range.startIndex 

    for _ in 0..<remainingCount 
    { range.endIndex = range.endIndex.successor() } 

    return range 
} 

,這裏是一個更快的一個:

func truncateTailsOfRange2<T>(var range: Range<T>, portion: Double) -> Range<T> 
{ 
    if range.isEmpty {return range} 
    let elements = Array(range) 
    let truncationCount = Int(portion * Double(elements.count)) 
    let remainingCount = max(0, elements.count - 2 * truncationCount) 
    return elements[truncationCount]..<elements[truncationCount+remainingCount] 
}