你如何将一个泛型类型称为它继承的类型之一?

huangapple go评论60阅读模式
英文:

How can you refer to a generic type as one it inherits from?

问题

我有一个名为MutableStorage的协议,它旨在存储泛型类型Item。我还有另一个协议ImmutableStorage,它继承自MutableStorage,旨在成为MutableStorage的只读版本。这部分功能正常。

我想要做的是将此存储指定为泛型,并在该类中同时访问可变类型和不可变类型。

例如,这个StorageExample类以泛型形式接受MutableStorage,并将其用于可变属性,这正是我想要的。问题出现在colectItems(:) 方法中,我更希望指定等效的ImmutableStorage 类型。

是否可以使用我定义的协议来实现这一点?或者答案是我不应该在MutableStorage/ImmutableStorage之间使用协议继承,而是需要将一个作为另一个的关联类型?

class StorageExample<S: MutableStorage> {
  private var mutableStorage: S
  init(mutableStorage: S) {
    self.mutableStorage = mutableStorage
  }

  func collectItems(_ collector: (S) -> [S.StorageItem]) {
    let itemUpdates = collector(mutableStorage) // <-- 我如何传递一个`ImmutableStorage` 类型
    for item in itemUpdates {
      mutableStorage.contents[item.key] = item
    }
  }
}

/// 可读/写的项目存储。
protocol MutableStorage: ImmutableStorage {
  var contents: [StorageItem.Key: StorageItem] { get set }
}

/// 可以检查但不能更改的项目存储。
protocol ImmutableStorage {
  associatedtype StorageItem: Item
  var contents: [StorageItem.Key: StorageItem] { get }
}

/// 可以存储的项目。
protocol Item {
  associatedtype Key: Hashable
  associatedtype Data
  var key: Key { get }
  var data: Data { get }
}
英文:

I have a MutableStorage protocol which is designed to store the generic Item type. I have another protocol ImmutableStorage which it inherits from, which is meant to be a read-only version of the MutableStorage. This part works fine.

What I would like to do is specify this storage as a generic and have access to both the mutable type and immutable types within that class.

For example, this StorageExample class takes the MutableStorage as a generic which it can use for its mutable property, which is exactly what I want. The problem I run into is in the colectItems(:) method where I would prefer to specify the equivalent ImmutableStorage type.

Is there a way to do this with the protocols I have defined? Or is the answer that I must not have the protocol inheritance between MutableStorage/ImmutableStorage and need to have one be an associated type of the other?

class StorageExample&lt;S: MutableStorage&gt; {
  private var mutableStorage: S
  init(mutableStorage: S) {
    self.mutableStorage = mutableStorage
  }

  func collectItems(_ collector: (S) -&gt; [S.StorageItem]) {
    let itemUpdates = collector(mutableStorage) // &lt;-- How can I pass an `ImmutableStorage` type
    for item in itemUpdates {
      mutableStorage.contents[item.key] = item
    }
  }
}

/// Read/write storage of the items.
protocol MutableStorage: ImmutableStorage {
  var contents: [StorageItem.Key: StorageItem] { get set }
}

/// Item storage that can be inspected but not changed.
protocol ImmutableStorage {
  associatedtype StorageItem: Item
  var contents: [StorageItem.Key: StorageItem] { get }
}

/// An item that can be stored.
protocol Item {
  associatedtype Key: Hashable
  associatedtype Data
  var key: Key { get }
  var data: Data { get }
}

答案1

得分: 1

If you intend for collector to accept an ImmutableStorage, you can pass that. I recommend adjusting your ImmutableStorage to have a primary type:

如果您打算让 `collector` 接受一个 ImmutableStorage,您可以传递它。我建议调整您的 ImmutableStorage 以具有主要类型:

```swift
protocol ImmutableStorage<StorageItem> {
    associatedtype StorageItem: Item
    var contents: [StorageItem.Key: StorageItem] { get }
}

In which case you can then pass a more appropriate collector:

在这种情况下,您可以传递一个更合适的 collector

func collectItems(_ collector: (任何 ImmutableStorage<S.StorageItem>) -> [S.StorageItem]) {

That said, this would probably be better implemented by passing the contents, which are a value type (and so the mutability doesn't matter):

话虽如此,通过传递内容来实现可能会更好,因为内容是一个值类型(所以可变性不重要):

func collectItems(_ collector: ([S.StorageItem.Key: S.StorageItem]) -> [S.StorageItem]) {
    let itemUpdates = collector(mutableStorage.contents)
    ...

希望这能帮助您。

英文:

If you intend for collector to accept an ImmutableStorage, you can pass that. I recommend adjusting your ImmutableStorage to a have a primary type:

protocol ImmutableStorage&lt;StorageItem&gt; {
    associatedtype StorageItem: Item
    var contents: [StorageItem.Key: StorageItem] { get }
}

In which case you can then pass a more appropriate collector:

func collectItems(_ collector: (any ImmutableStorage&lt;S.StorageItem&gt;) -&gt; [S.StorageItem]) {

That said, this would probably be better implemented by passing the contents, which are a value type (and so the mutability doesn't matter):

func collectItems(_ collector: ([S.StorageItem.Key: S.StorageItem]) -&gt; [S.StorageItem]) {
    let itemUpdates = collector(mutableStorage.contents)
    ...

答案2

得分: 0

以下是您要翻译的内容:

另一种解决方法是仅使用独立的协议,而不是不必要的继承。这使您可以通过关联类型直接引用不可变类型。

/// 可以检查但无法更改的项目存储。
protocol ImmutableStorage {
  associatedtype StorageItem: Item
  var contents: [StorageItem.Key: StorageItem] { get }
}

protocol MutableStorage {
  associatedtype Immutable: ImmutableStorage  // &lt;-- 可以引用不可变存储类型
  var contents: [Immutable.StorageItem.Key: Immutable.StorageItem] { get set }
  var readOnly: Immutable { get }
}

class StorageExample&lt;S: MutableStorage&gt; {

  func collectItems(_ collector: (S.Immutable) -&gt; [S.Immutable.StorageItem]) { 
    (...)
  }
}
英文:

Another solution to this is to just have separate protocols rather than unnecessary inheritance. This lets you refer to the immutable type directly via the associated type.

/// Item storage that can be inspected but not changed.
protocol ImmutableStorage {
  associatedtype StorageItem: Item
  var contents: [StorageItem.Key: StorageItem] { get }
}

protocol MutableStorage {
  associatedtype Immutable: ImmutableStorage  // &lt;-- Can refer to the Immutable storage type
  var contents: [Immutable.StorageItem.Key: Immutable.StorageItem] { get set }
  var readOnly: Immutable { get }
}

class StorageExample&lt;S: MutableStorage&gt; {

  func collectItems(_ collector: (S.Immutable) -&gt; [S.Immutable.StorageItem]) { 
    (...)
  }
}

huangapple
  • 本文由 发表于 2023年6月11日 23:21:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76451149.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定