为什么popFirst会抛出错误,但removeFirst有效吗?

时间:2018-04-08 23:12:30

标签: arrays swift struct immutability

struct Queue<T>{

    private var elements : [T] = []

    public mutating func enqueue(_ element: T){
        elements.append(element)
    }
    public mutating func dequeue() -> T?{
        return elements.popFirst()  // ERROR!
    }
    public mutating func dequeue2() -> T?{
        return elements.removeFirst()
    }
}

我为popFirst收到的错误是:

  

不能在不可变值上使用变异成员:&#39; self&#39;是   不可变

popFirstremoveFirst都标记为mutating,并且都返回T?。那么为什么它不起作用呢?

编辑:正如其他人评论的那样,它似乎是某种错误。它已在论坛here中进行了讨论。

编辑:仍然在Xcode 9.4.1(Swift 4.1.2)中发生

2 个答案:

答案 0 :(得分:2)

该错误在Swift 4.2中得到了改善:

error: ios.playground:4:25: error: '[T]' requires the types '[T]' and 'ArraySlice<T>' be equivalent to use 'popFirst'
        return elements.popFirst()  // ERROR!
                        ^

由于未为所有popFirst定义Collection,所以收到错误消息。仅当Collection是其自己的SubSequence类型时才定义。 Here's the implementation

extension Collection where SubSequence == Self {
  /// Removes and returns the first element of the collection.
  ///
  /// - Returns: The first element of the collection if the collection is
  ///   not empty; otherwise, `nil`.
  ///
  /// - Complexity: O(1)
  @inlinable
  public mutating func popFirst() -> Element? {
    // TODO: swift-3-indexing-model - review the following
    guard !isEmpty else { return nil }
    let element = first!
    self = self[index(after: startIndex)..<endIndex]
    return element
  }
}

我认为扩展名需要SubSequence == Self,因为self[index(after: startIndex)..<endIndex]返回了SubSequence,除非self(符合{ {1}}和它的Self是同一类型。

Collection的{​​{1}}类型是SubSequence,而不是Array,因此此扩展名不适用于SubSequence

答案 1 :(得分:1)

以下是您可能正在寻找的扩展名:

extension Array {
    @inlinable
    public mutating func popFirst() -> Element? {
        if isEmpty {
            return nil
        } else {
            return removeFirst()
        }
    }
}