英文:
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<S: MutableStorage> {
private var mutableStorage: S
init(mutableStorage: S) {
self.mutableStorage = mutableStorage
}
func collectItems(_ collector: (S) -> [S.StorageItem]) {
let itemUpdates = collector(mutableStorage) // <-- 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<StorageItem> {
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<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)
...
答案2
得分: 0
以下是您要翻译的内容:
另一种解决方法是仅使用独立的协议,而不是不必要的继承。这使您可以通过关联类型直接引用不可变类型。
/// 可以检查但无法更改的项目存储。
protocol ImmutableStorage {
associatedtype StorageItem: Item
var contents: [StorageItem.Key: StorageItem] { get }
}
protocol MutableStorage {
associatedtype Immutable: ImmutableStorage // <-- 可以引用不可变存储类型
var contents: [Immutable.StorageItem.Key: Immutable.StorageItem] { get set }
var readOnly: Immutable { get }
}
class StorageExample<S: MutableStorage> {
func collectItems(_ collector: (S.Immutable) -> [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 // <-- Can refer to the Immutable storage type
var contents: [Immutable.StorageItem.Key: Immutable.StorageItem] { get set }
var readOnly: Immutable { get }
}
class StorageExample<S: MutableStorage> {
func collectItems(_ collector: (S.Immutable) -> [S.Immutable.StorageItem]) {
(...)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论