这是我所拥有的:
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)
}
但是我得到的错误是:
Cannot invoke initializer for type
Double
with an argument list of type (T.Distance
)
这可以做到吗?
最佳答案
首先您需要一个 CustomDoubleConvertible
协议(protocol)。这反射(reflect)了 CustomStringConvertible
。您可以扩展所有想要转换为 Double
的类型。类似于返回类型的String
表示形式的description
。
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
必须是 Bi DirectionIndexType
,您可以使用 successor
和 前任
。
extension Range where Element.Distance : CustomDoubleConvertible, Element : BidirectionalIndexType {
这允许您通过迭代偏移量并调用successor
和predecessor
来获取完整的函数。
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
关于Swift:如何使这个函数通用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34972949/