【问题标题】:Why do I have to implement append<S: Sequence>(contentsOf newElements: S) in my custom RangeReplaceableCollection为什么我必须在我的自定义 RangeReplaceableCollection 中实现 append<S: Sequence>(contentsOf newElements: S)
【发布时间】:2018-04-13 12:36:01
【问题描述】:

我目前正在尝试将自定义集合类型更新为 Swift 4.1。 但是,当我遵守文档并实现CollectionRangeReplaceableCollection 的所有要求时,Xcode 仍然抱怨我的类型不符合RangeReplaceableCollection

Here'smcve 解决这个问题(Hamish 慷慨提供,谢谢你:)

class Foo<Element : AnyObject> {
  required init() {}
  private var base: [Element] = []
}

extension Foo : Collection {
  typealias Index = Int

  var startIndex: Index {
    return base.startIndex
  }

  var endIndex: Index {
    return base.endIndex
  }

  func index(after i: Index) -> Index {
    return base.index(after: i)
  }

  subscript(index: Index) -> Element {
    return base[index]
  }
}

extension Foo : RangeReplaceableCollection {
  func replaceSubrange<C : Collection>(
    _ subrange: Range<Index>, with newElements: C
  ) where Element == C.Element {}
}

According to the documentation,代码应该可以编译:

将 RangeReplaceableCollection 一致性添加到您的自定义 集合,添加一个空初始化器和 replaceSubrange(_:with:) 方法到您的自定义类型。 RangeReplaceableCollection 提供 使用它的所有其他方法的默认实现 初始化器和方法。

不幸的是,事实并非如此。相反,Xcode 会发出以下错误消息:

// error: type 'Foo<Element>' does not conform to protocol 'RangeReplaceableCollection'
// extension Foo : RangeReplaceableCollection {
// ^
//   Swift.RangeReplaceableCollection:5:26: note: candidate has non-matching type '<Self, S> (contentsOf: S) -> ()' [with SubSequence = Foo<Element>.SubSequence]
//   public mutating func append<S>(contentsOf newElements: S) where S : Sequence, Self.Element == S.Element
//                        ^
//   Swift.RangeReplaceableCollection:9:26: note: protocol requires function 'append(contentsOf:)' with type '<S> (contentsOf: S) -> ()'; do you want to add a stub?
//   public mutating func append<S>(contentsOf newElements: S) where S : Sequence, Self.Element == S.Element
//   

为了确保这不是文档中的错误,我检查了the source code of Swift 4.1 并在 RangeReplaceableCollection.swift 中找到了func append&lt;S&gt;(contentsOf newElements: S) where S: Sequence, Element == S.Element 的默认实现,第 442-452 行:

@_inlineable
public mutating func append<S : Sequence>(contentsOf newElements: S) where S.Element == Element {
  let approximateCapacity = self.count + numericCast(newElements.underestimatedCount)
  self.reserveCapacity(approximateCapacity)
  for element in newElements {
    append(element)
  }
}

问题:

  • 尽管提供了默认实现,为什么 Xcode 要求实现此功能?
  • 如何编译我的代码?

【问题讨论】:

  • 您的项目链接无效。通常,所有相关代码都必须包含在问题本身中(因为场外资源可能会变得不可用,从而使问题对未来的读者毫无用处)。
  • 您需要实现mutating func replaceSubrange&lt;C&gt;(_ subrange: Range&lt;Self.Index&gt;, with newElements: C) where C : Collection, Self.Element == C.Element 的要求(不是RangeExpression 的通用变体)。您能否提供minimal reproducible example 以便我们重现您的问题?
  • 抱歉,我修复了链接。我目前正在尝试实现一个最小、完整和可验证的示例,并将相应地更新问题。谢谢:)
  • 这是一个适合您的 mcve:gist.github.com/hamishknight/a7a8b2b70c8eff9efec2b4e6a94338f8。对我来说看起来像一个错误;如果您取消注释 required init&lt;S : Sequence&gt;func append&lt;S : Sequence&gt; 它会编译(如果您将类标记为 final 或在 Swift 4.0.3 中,它也会编译)。看起来需求中的通用占位符是问题所在。从错误消息的外观来看,我认为这实际上可能与 stackoverflow.com/q/49792626/2976878.. 中讨论的更改有关。有时间我会提交一个错误。
  • 非常感谢,您真好。同时,我还创建了一个 mcve,只是没有内联错误消息:gist.github.com/JanNash/ce344a40747b9fc38b83c14fa86247c2 // 我会尝试挽救这个问题。

标签: swift swift-protocols swift4.1


【解决方案1】:

尽管提供了默认实现,为什么 Xcode 要求实现此功能?

这是由于 Swift 4.1 中引入的 TypeChecker 中的错误:
[SR-7429]: Cannot conform a non-final class to a protocol with a defaulted requirement with a generic placeholder constrained to an associated type

如何让我的代码编译?

在修复错误之前,目前有三种方法可以编译它。

  • 实现这两个功能:

    • required init&lt;S : Sequence&gt;(_ elements: S) where Element == S.Element {}
    • func append&lt;S : Sequence&gt;(contentsOf newElements: S) where Element == S.Element
  • 将班级标记为final

  • 将集合类型实现为struct。为此,必须删除 required init() {}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    • 2021-08-07
    相关资源
    最近更新 更多