【问题标题】:Extend Collection: Array and Set, but not Dictionary扩展集合:数组和集合,但不是字典
【发布时间】:2020-12-16 00:34:56
【问题描述】:
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)
    }
}

【问题讨论】:

  • @Sweeper 好的,该怎么做?
  • 其实我们不需要这样的初始化器。代码:sequence.map(Array.init) 效果一样。
  • 是的,但我还是更喜欢初始化程序。只是看起来“更直接”:-)

标签: arrays swift collections set


【解决方案1】:

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

  • 具有Element 关联类型
  • 有一个接受Sequence的初始化程序

Sequence 满足第一个条件,ArraySet 之间没有满足第二个条件的通用协议:-(。来自Array 的那个来自RangeReplaceableCollection。来自@987654337 的那个@来自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)
    }
}

或者 (as you said) 如果你不介意写 mapinit,你可以直接写 sequence.map(Array.init)


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

【讨论】:

  • 我刚刚发现了这个解决方案的一个问题。它不起作用。它会导致我们的自定义初始化程序的无限递归调用。序列没有任何我们可以在展开可选后使用的初始化器。
  • @Roman 真的吗?我记得 Sequence 确实有一个初始化器,就像我的答案中的那个一样,除了它不是失败的并且接受一个非可选的。我现在在外面,所以我回来后会尝试一下,但我当然记得我在 2 个月前确认过这有效......
  • @Roman 我不敢相信我犯了这个错误!那天我的大脑一定没有工作!修复了一个不太优雅的解决方案,但至少它有效。
【解决方案2】:

你可以这样做:

protocol NilSequenceInitializable {}

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

extension Array: NilSequenceInitializable {}
extension Set: NilSequenceInitializable {}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-05
    • 2015-06-02
    • 1970-01-01
    • 2013-11-29
    • 2015-12-11
    相关资源
    最近更新 更多