[英]`Identifiable` conformance return type generic as variable
I'm trying to build an OutlineGroup
from this example from Apple: https://developer.apple.com/documentation/swiftui/outlinegroup我正在尝试从 Apple 的此示例构建
OutlineGroup
: https://developer.apple.com/documentation/swiftui/outlinegroup
But instead of using static types I want to use objects that conform to my protocol.但是,我不想使用 static 类型,而是想使用符合我的协议的对象。 So the question is more general if that's possible in swift what I'm trying to do:
因此,如果在 swift 中可行的话,这个问题就更笼统了:
I have protocol that gives me people coworkers
and name
from various objects:我有协议,可以为我提供来自各种对象的
coworkers
和name
:
protocol CastProtocol {
var name: String { get }
var coworkers: [CastProtocol]? { get } // here will be the build error later
}
And consider two models as example:并以两个模型为例:
class Actor: Identifiable, CastProtocol {
var id: Self { self }
var name: String { return "Chuck Norris" }
var coworkers: [CastProtocol]? {
return [
Director()
]
}
}
class Director: Identifiable, CastProtocol {
var id: Self { self }
var name: String { return "Gina Carey" }
var coworkers: [CastProtocol]? {
return [
Actor(),
Director(),
Actor()
]
}
}
So till now everything working, but I need to ensure that my CastProtocol
conforms to Identifiable
, so changing my protocol implementation to:所以到目前为止一切正常,但我需要确保我的
CastProtocol
符合Identifiable
,因此将我的协议实现更改为:
protocol CastProtocol: Identifiable {
...
}
And now this creates a problem:现在这产生了一个问题:
Protocol 'CastProtocol' can only be used as a generic constraint because it has Self or associated type requirements
协议“CastProtocol”只能用作通用约束,因为它具有 Self 或关联的类型要求
coworkers
or maybe I should go with subclassing?coworkers
中返回不是 static 类型,或者我应该 go 子类化?coworkers
in this example can contain Actor
or Director
associatedType I think cannot be usecoworkers
可以包含Actor
或Director
associatedType 我认为不能使用Protocols never conform to other protocols.协议从不符合其他协议。 The syntax
protocol CastProtocol: Identifiable
does not mean "CastProtocol conforms to Identifiable."语法
protocol CastProtocol: Identifiable
并不意味着“CastProtocol 符合 Identifiable”。 It means "in order to conform to CastProtocol, a type must also conform to Identifiable."它的意思是“为了符合 CastProtocol,一个类型也必须符合 Identifiable”。
To the question, though, no, you cannot require that.但是,对于这个问题,不,您不能要求这样做。
Identifiable
includes an associated type ID
. Identifiable
包括一个关联的类型ID
。 Consider this code:考虑这段代码:
let coworker in coworkers {
let id = coworker.id // What type is `id` here?
...
}
Swift cannot assign a single type type id
in this case.在这种情况下,Swift 无法分配单个类型类型
id
。 Someday they may add a feature called a Generalized Existential that would allow id
to be inferred to be the type Any where Self: Hashable
, but it's not currently possible to express that in Swift.有一天,他们可能会添加一个名为 Generalized Existential 的功能,该功能允许将
id
推断为Any where Self: Hashable
类型,但目前无法在 Swift 中表达。
But in your case, it couldn't work anyway.但在你的情况下,它无论如何都无法工作。 Say you could do this.
说你可以做到这一点。 Since you've made the identifier be the object itself, eventually the system would need to evaluate
Director == Actor
.由于您已将标识符设置为 object 本身,因此系统最终需要评估
Director == Actor
。 That's not possible in Swift.这在 Swift 中是不可能的。 Those aren't the same type.
那些不是同一类型。
Instead, I suspect you want this, if you really want Cast members to be classes:相反,如果您真的希望 Cast 成员成为类,我怀疑您想要这个:
protocol CastMember: class {
var name: String { get }
var coworkers: [CastMember] { get } // Optional Arrays are almost always wrong
var id: ObjectIdentifer { get }
}
extension CastMember {
var id: ObjectIdentifier { ObjectIdentifier(self) }
}
// You can still put Identifiable here for [Actor] properties
class Actor: CastProtocol, Identifiable {
// ...
}
Now, this won't let you put these directly into a ForEach(actor.coworkers)
call, which I assume is what you want.现在,这不会让您将这些直接放入
ForEach(actor.coworkers)
调用中,我认为这是您想要的。 Personally, I'd just pass the id: \.id
parameter, but you can of course make it a little nicer with an extension if you do this a lot:就个人而言,我只是传递
id: \.id
参数,但如果你经常这样做,你当然可以通过扩展使它更好一点:
extension ForEach where Content : View, Data.Element == CastMember {
public init(_ data: Data, @ViewBuilder content: @escaping (Data.Element) -> Content) {
self.init(data, id: \.id, content: content)
}
}
Note the Data.Element == CastMember
not :
.注意
Data.Element == CastMember
不是:
。 This applies when it's an array of CastMember, not an array of things that conform to CastMember.这适用于 CastMember 数组,而不是符合 CastMember 的事物数组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.