使用自定义比较函数时,无法将“[ExpressionColumn]”类型的值转换为预期参数类型“Binding<C>””

问题描述 投票:0回答:1

我在 SwiftUI 中遇到一个问题,我尝试使用 ForEach 循环来迭代结构数组 (v.columns) 并根据条件更新属性。这些结构具有 [Any] 类型的 expressionKeypathSegment 属性,我尝试使用自定义比较函数 (compareArrays) 来确定循环内按钮的背景颜色。

这是代码的简化版本:

ForEach(v.columns, id: \.index) { v2 in
    if v2.isBtnStyle {
        Button(action: {
            expressionKeypathSegment = v2.expressionKeypathSegment
        }) {
            Text(v2.text)
                .padding(EdgeInsets(top: 4, leading: 16, bottom: 4, trailing: 16))
                .foregroundColor(.white)
                .background(/*compareArrays(expressionKeypathSegment, v2.expressionKeypathSegment) ? Color.purple :*/ Color.blue)
                .cornerRadius(8)
        }
    } else {
        Text(v2.text)
    }
}

当我用compareArrays 取消注释该行时,出现错误:“无法将类型‘[ExpressionColumn]’的值转换为预期的参数类型‘Binding’”。注释掉这一行可以解决问题,表明问题可能与compareArrays的使用有关。

这是compareArrays的实现:

func compareArrays<T: Equatable>(_ array1: [T], _ array2: [T]) -> Bool {
    guard array1.count == array2.count else {
        return false
    }

    for (element1, element2) in zip(array1, array2) {
        guard type(of: element1) == type(of: element2) else {
            return false
        }

        guard element1 == element2 else {
            return false
        }
    }

    return true
}

我怀疑这个问题可能与 ExpressionColumn 如何处理相等或泛型的使用有关。任何关于为什么会发生此错误以及我如何解决它的见解将不胜感激。谢谢!

您可以根据您的具体情况随意定制问题,并提供任何可能相关的其他详细信息。

swift swiftui
1个回答
0
投票

你的问题是 Any 类型不符合 Equatable 协议,在我的例子中编译器对此非常清楚。 此外,您的代码不容易在其他人的机器上进行测试。仅仅复制它并将其粘贴到 XCode 中是不够的,我必须进行许多编辑才能使其工作,并找到一种重新编码代码结构的方法。 顺便说一句,我让它工作了,但正如我所说,我无法使用 Any,因为它不是 Equatable。这是我的代码版本:

struct ContentView: View {
    
    @StateObject private var trialStruct = TrialStruct()
    @State private var expressionKeypathSegment: [Int]?
    
    var body: some View {
        VStack {
            ForEach($trialStruct.columns, id: \.id) { v2 in
                if v2.isBtnStyle.wrappedValue {
                    Button(action: {
                        expressionKeypathSegment = v2.expressionKeypathSegment.wrappedValue
                    }) {
                        Text(v2.text.wrappedValue)
                            .padding(EdgeInsets(top: 4, leading: 16, bottom: 4, trailing: 16))
                            .foregroundColor(.white)
                            .background(compareArrays(expressionKeypathSegment ?? [0], v2.expressionKeypathSegment.wrappedValue) ? Color.purple : Color.blue)
                            .cornerRadius(8)
                    }
                } else {
                    Text(v2.text.wrappedValue)
                }
            }
        }
        .onAppear {
            trialStruct.columns = [
                .init(index: 0, expressionKeypathSegment: ["1"], isBtnStyle: true, text: "Hello"),
                .init(index: 1, expressionKeypathSegment: ["2"], isBtnStyle: false, text: "Hello"),
            ]
        }
    }
    
    func compareArrays<T: Equatable>(_ array1: [T], _ array2: [T]) -> Bool {
        guard array1.count == array2.count else {
            return false
        }

        for (element1, element2) in zip(array1, array2) {
            guard type(of: element1) == type(of: element2) else {
                return false
            }

            guard element1 == element2 else {
                return false
            }
        }

        return true
    }
}

class TrialStruct: ObservableObject {
    
    @Published var columns = [Column]()
    
}

struct Column: Identifiable {
    
    var id = UUID()
    var index: Int
    var expressionKeypathSegment: [Int]
    var isBtnStyle: Bool
    var text: String
    
    init(id: UUID = UUID(), index: Int, expressionKeypathSegment: [Int], isBtnStyle: Bool, text: String) {
        self.id = id
        self.index = index
        self.expressionKeypathSegment = expressionKeypathSegment
        self.isBtnStyle = isBtnStyle
        self.text = text
    }
    
    init(id: UUID = UUID(), index: Int, expressionKeypathSegment: [String], isBtnStyle: Bool, text: String) {
        self.id = id
        self.index = index
        self.expressionKeypathSegment = expressionKeypathSegment.map({ Int($0) ?? 0 })
        self.isBtnStyle = isBtnStyle
        self.text = text
    }
    
}

我使用了 String 而不是 Any,您可以使用最适合您需求的类型。 该代码似乎按预期工作。一旦我点击 isBtnStyle 为 true 的按钮,它就会变成紫色:

© www.soinside.com 2019 - 2024. All rights reserved.