SwiftUI - 显示符合协议的元素并对元素使用 == 的视图

SwiftUI - View showing Elements conforming to a Protocol and and using == for the Elements

我需要在视图中显示符合通用协议的不同结构的数组。
按照 中的建议,我试过了 - 它工作正常!

现在我需要检查数组元素的相等性。
让协议符合 Equatable 不编译 -
它收到错误:Protocol 'Suggest' can only be used as a generic constraint because it has Self or associated type requirements.

//protocol Suggest :Equatable {
protocol Suggest  {
  var desc: String { get }
}

struct Person : Suggest {
  var surname : String
  var name: String
  
  var id: String { return name }
  var desc: String { return name }
}

struct Book : Suggest {
  var titel : String
  var abstact : String
  
  var id: String { return titel }
  var desc: String { return titel }
}


let books = [ Book(titel: "book 1", abstact: "abstract1"),
              Book(titel: "book 2", abstact: "abstract2")
            ]

let persons = [ Person(surname: "John", name: "Doe"),
                Person(surname: "Susan", name: "Smith"),
                Person(surname: "Frank", name: "Miller")
              ]


struct ContentView: View {
  var body: some View {
    VStack {
      SuggestList(list: books)
      SuggestList(list: persons)
    }
  }
}

struct SuggestList: View {
  var list : [Suggest]
// this line does not compile, if Suggest conforms to Equitable
// "Protocol 'Suggest' can only be used as a generic constraint because it has Self or associated type requirements" 
  
  var body: some View {
    List(list.indices, id: \.self) { index in
      Text(list[index].desc)
//        .onTapGesture {
//          if list.contains(list[index]){print ("hello")}
//        }
    }
  }
}

你需要使用 <SuggestType: Suggest> 并制作 Suggest 协议 Equatable 然后使用并定义 = = 个人书籍


struct ContentView: View {
    var body: some View {
        VStack {
            SuggestList(list: books)
            SuggestList(list: persons)
        }
    }
}

protocol Suggest: Equatable  {
    var desc: String { get }
}

struct Person: Suggest {
    
    var surname: String
    var name: String
    
    var id: String { return name }
    var desc: String { return name }
    
    
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name
    }
    
}

struct Book: Suggest {
    
    var titel: String
    var abstact: String
    
    var id: String { return titel }
    var desc: String { return titel }
    
    static func == (lhs: Book, rhs: Book) -> Bool {
        return lhs.titel == rhs.titel
    }
    
    
}



let persons = [Person(surname: "John", name: "Doe"),
               Person(surname: "Susan", name: "Smith"),
               Person(surname: "Frank", name: "Miller")]


let books = [Book(titel: "book 1", abstact: "abstract1"),
             Book(titel: "book 2", abstact: "abstract2")]




struct SuggestList<SuggestType: Suggest>: View {
    
    var list : [SuggestType]

    
    var body: some View {
        List(list.indices, id: \.self) { index in
            Text(list[index].desc)
                .onTapGesture {
                    if list.contains(list[index]){ print(list[index].desc) }
                }
        }
    }
}

本回答属于评论区问题!关于 Equatable 函数。

如果你没有显式定义 Equatable 函数,那么 Xcode 如果它可以自己推断它会自行处理,有时在复杂的结构中它会要求你显示它当你的结构实例是相等,但是当你显式定义 Equatable 函数时 Xcode 将应用你的自定义规则,例如我创建了 2 种类型的人,在第一个 PersonV1 中我们没有定义 == 但在第二个 PersonV2 中我们确实定义了!因此,Xcode 将在 PersonV2 中接受所有具有相同姓名的人,即使他们有不同的 姓氏 。尝试使用此代码以获得更真实的测试示例。并且 surnamePersonV2 中的任何更新都不会占据任何位置,因为它不会计算 PersonV2 的 2 个实例 是否相等!一旦您初始化了 PersonV2 的实例,surname 将不再可更新。您可以尝试更新,但它不会应用,因为无论此实例是否相同,都无所谓!

注意: 我们可以使用此代码使 PersonV2 相等函数对姓氏更改做出反应,但我认为您想像问题中那样使用名称:

static func == (lhs: PersonV2, rhs: PersonV2) -> Bool {
    return lhs.name == rhs.name && lhs.surname == rhs.surname
}



struct ContentView: View {

    @State private var person1: PersonV1 = PersonV1(surname: "Frank", name: "Miller")
    @State private var person2: PersonV2 = PersonV2(surname: "John", name: "Doe")

    var body: some View {
        
        VStack(spacing: 50.0) {
        
        VStack(spacing: 20.0) {

            Button("update name of person1") { person1.name += " updated!" }
            Button("update surname of person1") { person1.surname += " updated!" }

        }
        .padding()
        .background(Color.yellow)
        .onChange(of: person1) { newValue in print("onChange for person1:", newValue) }
        
        
        
        
        VStack(spacing: 20.0) {

            Button("update name of person2") { person2.name += " updated!" }
            Button("update surname of person2") { person2.surname += " updated!" }

        }
        .padding()
        .background(Color.red)
        .onChange(of: person2) { newValue in print("onChange for person2:", newValue) }
        
        }
        
    }
}

protocol Suggest: Equatable  {
    var desc: String { get }
}



struct PersonV1: Suggest {
    
    var surname: String
    var name: String
    
    var id: String { return name }
    var desc: String { return name }
   
}


struct PersonV2: Suggest {
    
    var surname: String
    var name: String
    
    var id: String { return name }
    var desc: String { return name }

    static func == (lhs: PersonV2, rhs: PersonV2) -> Bool {
        return lhs.name == rhs.name
    }
    
}