You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI自定义泛型组件报错:无法将[ASValue<T>]转为Binding<C>

解决SwiftUI中自定义泛型类型结合ForEach的类型转换错误

你遇到的错误源于编译器对ForEach重载的歧义判断,同时代码中存在多处类型不匹配问题,导致无法正确推断参数类型。以下是具体修复方案:

修复步骤

1. 明确ForEach的唯一标识

将ASValue中的私有id改为public,直接用该UUID作为ForEach的唯一标识,避免Hashable协议带来的重载混淆:

public struct ASValue<T: Hashable>: Hashable {
    public let id = UUID() // 修改为public
    var item: T
    
    public init(item: T) {
        self.item = item
    }
}

之后在ForEach中指定id: \.id:

ForEach(section.items, id: \.id) { item in
    // 内容
}

2. 修正类型不匹配问题

代码中有3处类型不匹配的地方,需逐一调整:

  • Text(display(item)) → Text(display(item.item)):display需要T类型参数,需取出ASValue<T>内部的item属性
  • values.selected.item = item → values.selected = item:selected是ASValue<T>类型,直接赋值整个实例即可
  • if values.selected.item == item → if values.selected == item:直接比较两个ASValue<T>实例(已实现Hashable协议)

修改后的完整代码

public struct ArrayStepperSection<T: Hashable>: Hashable {
    public let header: String
    public var items: [ASValue<T>]
    
    public init(header: String = "", items: [ASValue<T>]) {
        self.header = header
        self.items = items
    }
}

public struct ASValue<T: Hashable>: Hashable {
    public let id = UUID()
    var item: T
    
    public init(item: T) {
        self.item = item
    }
}

public class ArrayStepperValues<T: Hashable>: Hashable, ObservableObject {
    @Published public var values: [ASValue<T>]
    @Published public var selected: ASValue<T>
    @Published public var sections: [ArrayStepperSection<T>]
    
    public init(values: [ASValue<T>], selected: ASValue<T>, sections: [ArrayStepperSection<T>]? = nil) {
        self.values = values
        self.selected = selected
        
        self.sections = sections ?? [ArrayStepperSection(items: values)] // 简化可选绑定逻辑
    }
    
    public static func == (lhs: ArrayStepperValues<T>, rhs: ArrayStepperValues<T>) -> Bool {
        return lhs.sections == rhs.sections
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(sections)
    }
}

struct ArrayStepperList<T: Hashable>: View {
    @Environment(\.dismiss) var dismiss
    
    @ObservedObject var values: ArrayStepperValues<T>
    
    let display: (T) -> String
    
    var body: some View {
        List {
            ForEach(values.sections, id: \.self) { section in
                Section(section.header) {
                    ForEach(section.items, id: \.id) { item in
                        Button(action: {
                            values.selected = item
                            dismiss()
                        }) {
                            HStack {
                                Text(display(item.item))
                                
                                Spacer()
                                
                                if values.selected == item {
                                    Image(systemName: "checkmark")
                                }
                            }
                        }
                    }
                }
            }
        }
        .listStyle(InsetGroupedListStyle())
        .navigationTitle(Text(display(values.selected.item)))
    }
}

内容的提问来源于stack exchange,提问作者Joe Scotto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 22:27:30