Swift:如何使这个函数通用

标签 swift generics

这是我所拥有的:

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 {

这允许您通过迭代偏移量并调用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

关于Swift:如何使这个函数通用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34972949/

相关文章:

generics - 如何将LanguagePrimitives.GenericZero/get_Zero添加到System.String?

c# - 从类创建数据表(不是实例列表)

ios - Storyboard View (iphone 4/5/6)影响集合单元格大小的布局(以编程方式设置)

ios - CLGeocoder().reverseGeocodeLocation;处理程序应该是什么?

ios - 显示和弹出多个 View Controller

c# - 如何将变量定义为类型列表<<>f_AnonymousType1<string,string>>

c# - 我的通用类型转换器味道不好,运行时异常,对象包罗万象,拳击等

c# - 转换为通用基类失败

swift - 解析错误代码 151

objective-c - Objective-C 依赖项的弃用警告