RangeReplaceableCollection 一致性不需要......实际上任何东西
RangeReplaceableCollection conformance doesn't require... actually anything
根据文档:
To add RangeReplaceableCollection conformance to your custom
collection, add an empty initializer and the replaceSubrange(_:with:)
method to your custom type.
但实际上并不需要! (空初始值设定项除外)
// Just stubs for minimal reproducible code
struct Category: Hashable {}
struct Product {}
struct ProductCollection {
typealias DictionaryType = [Category : [Product]]
// Underlying, private storage
private var products = DictionaryType()
// Enable our collection to be initialized with a dictionary
init(products: DictionaryType = DictionaryType()) {
self.products = products
}
}
extension ProductCollection: Collection {
// Required nested types, that tell Swift what our collection contains
typealias Index = DictionaryType.Index
typealias Element = DictionaryType.Element
// The upper and lower bounds of the collection, used in iterations
var startIndex: Index { return products.startIndex }
var endIndex: Index { return products.endIndex }
// Required subscript, based on a dictionary index
subscript(index: Index) -> Iterator.Element {
get { return products[index] }
}
// Method that returns the next index when iterating
func index(after i: Index) -> Index {
return products.index(after: i)
}
}
extension ProductCollection: ExpressibleByDictionaryLiteral {
init(dictionaryLiteral elements: (Category, [Product])...) {
self.init(products: .init(uniqueKeysWithValues: elements))
}
}
extension ProductCollection: RangeReplaceableCollection {
init() {
products = DictionaryType()
}
// func replaceSubrange<C: Collection, R: RangeExpression>(_ subrange: R, with newElements: C)
// where Self.Element == C.Element, Self.Index == R.Bound {
// }
}
代码取自一个很棒的(但与post的主题无关)John Sundell article。
即使未提供 replaceSubrange
函数,此代码也会编译。
还有一个问题。为什么我应该在这种情况下显式提供一个空的初始化程序?我可以像 ProductCollection()
这样初始化结构而无需该初始化程序。我可以这样做有很多原因:1) products
属性 提供了初始化值 2) 主初始化器提供了默认值 3) 还有一个 ExpressibleByDictionaryLiteral 初始化器可以用来初始化一个空对象。
那么为什么我必须显式地再提供一个空的初始值设定项?
但是请注意,关于 replaceSubrange
函数的第一个问题更为重要 :)
这是 Swift 论坛中也讨论过的错误:
- SR-6501 RangeReplaceableCollection default implementations cause infinite recursion
- 编译器允许我使用不完整的 RangeReplaceableCollection
使用 Swift
原因是 replaceSubRange()
方法(将 RangeExpression
作为第一个参数)的 overload 被编译器错误地接受为满足协议要求。
但请注意,即使代码在没有实现所需方法的情况下编译通过,它也不起作用并导致无限循环。这是一个简短的例子:
struct MyCollection : MutableCollection {
private var storage: [Int] = []
init(_ elements: [Int]) { self.storage = elements }
var startIndex : Int { return 0 }
var endIndex : Int { return storage.count }
func index(after i: Int) -> Int { return i + 1 }
subscript(position : Int) -> Int {
get { return storage[position] }
set(newElement) { storage[position] = newElement }
}
}
extension MyCollection: RangeReplaceableCollection {
init() { }
}
var mc = MyCollection([0, 1, 2, 3, 4, 5])
mc.replaceSubrange(0..<3, with: [2, 3, 4])
运行 该代码会导致“无限”循环,并最终因堆栈溢出 EXC_BAD_ACCESS 而崩溃。
根据文档:
To add RangeReplaceableCollection conformance to your custom collection, add an empty initializer and the replaceSubrange(_:with:) method to your custom type.
但实际上并不需要! (空初始值设定项除外)
// Just stubs for minimal reproducible code
struct Category: Hashable {}
struct Product {}
struct ProductCollection {
typealias DictionaryType = [Category : [Product]]
// Underlying, private storage
private var products = DictionaryType()
// Enable our collection to be initialized with a dictionary
init(products: DictionaryType = DictionaryType()) {
self.products = products
}
}
extension ProductCollection: Collection {
// Required nested types, that tell Swift what our collection contains
typealias Index = DictionaryType.Index
typealias Element = DictionaryType.Element
// The upper and lower bounds of the collection, used in iterations
var startIndex: Index { return products.startIndex }
var endIndex: Index { return products.endIndex }
// Required subscript, based on a dictionary index
subscript(index: Index) -> Iterator.Element {
get { return products[index] }
}
// Method that returns the next index when iterating
func index(after i: Index) -> Index {
return products.index(after: i)
}
}
extension ProductCollection: ExpressibleByDictionaryLiteral {
init(dictionaryLiteral elements: (Category, [Product])...) {
self.init(products: .init(uniqueKeysWithValues: elements))
}
}
extension ProductCollection: RangeReplaceableCollection {
init() {
products = DictionaryType()
}
// func replaceSubrange<C: Collection, R: RangeExpression>(_ subrange: R, with newElements: C)
// where Self.Element == C.Element, Self.Index == R.Bound {
// }
}
代码取自一个很棒的(但与post的主题无关)John Sundell article。
即使未提供 replaceSubrange
函数,此代码也会编译。
还有一个问题。为什么我应该在这种情况下显式提供一个空的初始化程序?我可以像 ProductCollection()
这样初始化结构而无需该初始化程序。我可以这样做有很多原因:1) products
属性 提供了初始化值 2) 主初始化器提供了默认值 3) 还有一个 ExpressibleByDictionaryLiteral 初始化器可以用来初始化一个空对象。
那么为什么我必须显式地再提供一个空的初始值设定项?
但是请注意,关于 replaceSubrange
函数的第一个问题更为重要 :)
这是 Swift 论坛中也讨论过的错误:
- SR-6501 RangeReplaceableCollection default implementations cause infinite recursion
- 编译器允许我使用不完整的 RangeReplaceableCollection 使用 Swift
原因是 replaceSubRange()
方法(将 RangeExpression
作为第一个参数)的 overload 被编译器错误地接受为满足协议要求。
但请注意,即使代码在没有实现所需方法的情况下编译通过,它也不起作用并导致无限循环。这是一个简短的例子:
struct MyCollection : MutableCollection {
private var storage: [Int] = []
init(_ elements: [Int]) { self.storage = elements }
var startIndex : Int { return 0 }
var endIndex : Int { return storage.count }
func index(after i: Int) -> Int { return i + 1 }
subscript(position : Int) -> Int {
get { return storage[position] }
set(newElement) { storage[position] = newElement }
}
}
extension MyCollection: RangeReplaceableCollection {
init() { }
}
var mc = MyCollection([0, 1, 2, 3, 4, 5])
mc.replaceSubrange(0..<3, with: [2, 3, 4])
运行 该代码会导致“无限”循环,并最终因堆栈溢出 EXC_BAD_ACCESS 而崩溃。