当您想使用index.advanceBy时,您应该使用什么类型?

时间:2016-01-16 17:00:15

标签: arrays swift indexof

我想在数组中的另一个对象附近找到一些对象。我以为我可以编写这样的扩展方法,但是我收到了这个错误:

// Error: Cannot invoke 'advanceBy' with an argument list of type '(Int)'

Int类型显然是错误的,但indexOf方法采用Self.Distance参数,我不知道如何将其用作参数类型。

extension CollectionType where Generator.Element : Equatable {
    func objectNear(object: Self.Generator.Element, indexModifier: Int) -> Self.Generator.Element? {
        if let index = self.indexOf(object) {
            let newIndex = index.advancedBy(indexModifier) // this doesn't work
            //let newIndex = index.advancedBy(1) // but this this works
            if self.indices.contains(newIndex) {
                return self[newIndex]
            }
        }
        return nil
    }
}

(如果有更多Swifty方法,我会很高兴听到它,但我想在任何情况下理解上述内容。)

1 个答案:

答案 0 :(得分:4)

CollectionType有方法

public func indexOf(element: Self.Generator.Element) -> Self.Index?

并符合

public protocol Indexable {
    typealias Index : ForwardIndexType
    // ...
}

最后,ForwardIndexType有方法

public func advancedBy(n: Self.Distance) -> Self

因此正确的类型是Index.Distance

func objectNear(object: Self.Generator.Element, indexModifier: Index.Distance) -> Self.Generator.Element? { ... }

但请注意,推动指数超过endIndex会崩溃, 例如对于角色集合:

let c = "abc".characters
print(c.objectNear("b", indexModifier: 1)) // Optional("c")
print(c.objectNear("b", indexModifier: 2)) // nil
print(c.objectNear("b", indexModifier: 3)) // fatal error: can not increment endIndex

一个安全的变体是:

func objectNear(object: Generator.Element, indexModifier: Index.Distance) -> Generator.Element? {
    if let index = indexOf(object) {
        if indexModifier > 0 && index.distanceTo(endIndex) <= indexModifier {
            return nil
        }
        if indexModifier < 0 && startIndex.distanceTo(index) < -indexModifier {
            return nil
        }
        return self[index.advancedBy(indexModifier)]
    }
    return nil
}

或者,如果您需要仅针对集合的方法 由Int(例如Array)编制索引,然后您可以定义

extension CollectionType where Generator.Element : Equatable, Index == Int {

    func objectNear(object: Generator.Element, indexModifier: Int) -> Generator.Element? {
        if let index = self.indexOf(object) {
            let newIndex = index + indexModifier
            if indices.contains(newIndex) {
                return self[newIndex]
            }
        }
        return nil
    }
}