首页 > 解决方案 > 扩展集合:数组和集合,但不是字典

问题描述

extension Array {
    init?<S: Sequence>(_ sequence: S?) where S.Element == Element {
        guard let sequence = sequence else { return nil }
        self.init(sequence)
    }
}

extension Set {
    init?<S: Sequence>(_ sequence: S?) where S.Element == Element {
        guard let sequence = sequence else { return nil }
        self.init(sequence)
    }
}

如您所见,两个扩展中的代码完全相同。那么如何在不重复的情况下重写它呢?就像是:

extension Collection where type == Array || type == Set {
    init?<S: Sequence>(_ sequence: S?) where S.Element == Element {
        guard let sequence = sequence else { return nil }
        self.init(sequence)
    }
}

标签: arraysswiftcollectionsset

解决方案


您要添加到Arrays 和Sets 的初始化程序实际上可以添加到 all Sequences,因为您没有使用Arrayor中唯一的任何内容Set。初始化程序所依赖的所有内容是:

  • 具有Element关联类型
  • 有一个初始化器,它需要一个Sequence

SequenceArray满足第一个标准,并且两者之间没有Set满足第二个标准的通用协议:-(。来自的一个Array来自RangeReplaceableCollection。来自的一个Set来自SetAlgebra

您可以自己创建这样的协议:

protocol SequenceInitialisable : Sequence {
    init<S: Sequence>(_ s: S) where S.Element == Element
}

extension Array : SequenceInitialisable {}
extension Set : SequenceInitialisable {}

extension SequenceInitialisable {
    init?<S: Sequence>(_ sequence: S?) where S.Element == Element {
        guard let sequence = sequence else { return nil }
        self.init(sequence)
    }
}

或者(如你所说sequence.map(Array.init)如果你不介意写mapinit


关于编写扩展的提示:尝试找到你的扩展所依赖/需要的所有东西,然后找到包含所有这些东西的最通用类型。那是你应该写扩展的类型。


推荐阅读