[英]any Identifiable can't conform to 'Identifiable'
update: add same error about Hashable更新:添加关于 Hashable 的相同错误
I have created an Identifiable
compliant protocol and compliant structures.我创建了一个可
Identifiable
的兼容协议和兼容结构。 Then, when I create the list and reference it in ForEach
, I get the error Type 'any TestProtocol' cannot conform to 'Identifiable'
(I get the same error about Hashable
).然后,当我创建列表并在
ForEach
中引用它时,我收到错误Type 'any TestProtocol' cannot conform to 'Identifiable'
(我收到关于Hashable
的相同错误)。
How should I fix this program?我应该如何修复这个程序?
If I write ForEach(list, id: \.id)
, it works, but I don't think it makes sense to be Identifiable compliant.如果我写
ForEach(list, id: \.id)
,它可以工作,但我认为符合 Identifiable 没有意义。
import SwiftUI
protocol TestProtocol: Identifiable, Hashable {
var id: UUID { get set }
var name: String { get set }
func greeting() -> String
static func == (lhs: Self, rhs: Self) -> Bool
}
extension TestProtocol {
static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.id == rhs.id
}
}
struct Person: TestProtocol {
var id = UUID()
var name: String
func greeting() -> String {
return "my name is \(name) and I'm a human."
}
}
struct Dog: TestProtocol {
var id = UUID()
var name: String
func greeting() -> String {
return "my name is \(name) and I'm a dog."
}
}
struct ContentView: View {
var list: [any TestProtocol] = [Person(name: "p1"), Dog(name: "d1")]
@State var selected: any TestProtocol
var body: some View {
VStack {
Picker(selection: $selected) { // Type 'any TestProtocol' cannot conform to 'Hashable'
ForEach(list) { l in // Type 'any TestProtocol' cannot conform to 'Identifiable'
Text(l.greeting()).tag(l) // Type 'any TestProtocol' cannot conform to 'Hashable'
}
} label: {
Text("select")
}
}
}
}
Your error message complaining about Hashable
is a "red hering".您抱怨
Hashable
的错误消息是“红色的”。 The protocol TestProtocol
, and therefor all structs conforming to it, conforms to Hashable
.协议
TestProtocol
以及所有符合它的结构都符合Hashable
。
let person = Person(name: "IAmHashable")
print(person.hashValue)
The reason this is failing is within the Picker
.失败的原因是在
Picker
中。 It needs a concrete type and not a protocol.它需要具体类型而不是协议。 One solution would be to create a "Container" type and a custom binding that handles this.
一种解决方案是创建“容器”类型和处理此问题的自定义绑定。
struct Container: Identifiable, Hashable{
//implement the same equality as in your TestProtocol
static func == (lhs: Container, rhs: Container) -> Bool {
rhs.wrapped.id == lhs.wrapped.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(wrapped)
}
var wrapped: any TestProtocol
//for convenience
var id: UUID {wrapped.id}
}
and the ContentView:和内容视图:
struct ContentView: View {
let startArr: [any TestProtocol] = [Person(name: "p1"), Dog(name: "d1")]
@State private var selected: (any TestProtocol)?
var body: some View {
// list of wrapped protocols
var list: [Container] = { startArr.map{Container(wrapped: $0)}}()
// binding
let selectionBinding: Binding<Container> = .init {
let returninstance = list.first { cont in
cont.id == selected?.id
}
return returninstance ?? list[0]
} set: { container in
selected = container.wrapped
}
// viewCode
VStack {
Picker(selection: selectionBinding) {
ForEach(list) { l in
Text(l.wrapped.greeting())
.tag(l)
}
} label: {
Text("select")
}
// confirmation selection changed
Text(selected?.name ?? "no Selection")
}
}
}
This solution has a few drawbacks :该解决方案有一些缺点:
startArr
should never be empty, else return returninstance?? list[0]
startArr
不应该为空,否则return returninstance?? list[0]
return returninstance?? list[0]
will break you code. return returninstance?? list[0]
会破坏你的代码。 This can be handled, but I think this is out of the scope of this question.Container
needs to be the same as in TestProtocol
as you cannot compare two any Protocol
s Container
的相等性比较需要与TestProtocol
中的相同,因为您无法比较两个any Protocol
sContainerView
selected
will be nil until something is selected.ContainerView
的外观上selected
将为零。 Any usage, eg: the Text
element in this case, needs to deal with this.Text
元素,都需要处理这个问题。 But you could probably set this in .onApear
..onApear
中设置它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.