【问题标题】:Collections of protocol instances协议实例的集合
【发布时间】:2015-04-14 21:24:51
【问题描述】:

尝试solve a problem 暂时无关紧要,我尝试在 Swift 中做一些在 C# 代码中很正常的事情:定义几个协议来描述生产者-消费者关系,然后提供具体的实现制作人:

protocol Consumer
{
  func someInterestingThing( producer: Producer )

  func anotherInterestingThing( producer: Producer, happenedBefore: Bool )
}

protocol Producer
{
  func addConsumer( consumer: Consumer )

  func removeConsumer( consumer: Consumer )
}


class ConcreteProducer : Producer
{
  private var _consumers = Set<Consumer>()

  func addConsumer( consumer: Consumer ) {
    _consumers.insert(consumer);
  }

  func removeConsumer( consumer: Consumer ) {
    _consumers.remove(consumer);
  }
}

这不起作用,因为我的 Consumer 协议不是 Hashable,它必须是进入 Swift Set。 (在 C# 中,这不会出现,因为 所有 对象都继承了 hashable-nature。)

好的,所以我将我的协议定义为从 Hashable 继承;不完全优雅,但应该工作。没有!现在我使用它的所有地方,我都得到了:

error: protocol 'Consumer' can only be used as a generic constraint
because it has Self or associated type requirements

显然,这是因为Hashable 继承了Equatable,它在自身上定义了==。从字面上看是Self,其中一些extra restrictions 说明了如何使用该类型。

也许有一些我还没有理解的泛型魔法可以让我声明集合和编译器会满意的类型的方法?

我可能会尝试做一些有味道的事情,比如用更抽象的术语定义存储,并在 add 和 remove 方法上强制协议一致性。但是AnyObject 没有实现Hashable。 (有没有更好的选择?)

我可以尝试将消费者封装在实现 Hashable 的私有包装器中,但我需要能够比较这些包装器,这取决于消费者的身份,然后看起来我'我在同一条船上。

我想要的只是将一堆这些东西放在一个集合中,而不需要知道更多关于它们的信息,而不是绝对必要的。我该怎么做?

【问题讨论】:

    标签: swift generics collections


    【解决方案1】:

    这个怎么样?

    protocol Consumer: class {
        func someInterestingThing( producer: Producer )
        func anotherInterestingThing( producer: Producer, happenedBefore: Bool )
    }
    
    protocol Producer {
        func addConsumer( consumer: Consumer )
        func removeConsumer( consumer: Consumer )
    }
    
    class ConcreteProducer : Producer {
        private var _consumers = [ObjectIdentifier:Consumer]()
    
        func addConsumer( consumer: Consumer ) {
            _consumers[ObjectIdentifier(consumer)] = consumer
        }
    
        func removeConsumer( consumer: Consumer ) {
            _consumers[ObjectIdentifier(consumer)] = nil
        }
    }
    
    • Consumer 声明为class 唯一协议
    • 使用Dictionary&lt;ObjectIdentifier, Consumer&gt; 而不是Set&lt;Consumer&gt;

    【讨论】:

    • 哦,我错过了书中提到纯类协议的部分。这是一个有用的技巧。在这种特定情况下,我猜消费者很可能实际上是对象而不是结构。但如果有更通用的解决方案来解决这个问题,那就太好了。
    猜你喜欢
    • 1970-01-01
    • 2019-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-31
    相关资源
    最近更新 更多