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

如何让SwiftUI可复用列表支持Text兼容的OrderedSet元素类型

如何让SwiftUI组件仅接受可用于Text视图的OrderedSet元素类型

问题描述

我需要创建一个可复用SwiftUI组件,用于展示OrderedSet集合,同时支持删除、移动和添加操作。要求传入的OrderedSet元素类型可以直接用于Text的字符串插值,比如Text("hello \(字符串、整数或浮点数这类泛型类型) world")。

原本尝试用ExpressibleByStringInterpolation协议约束元素类型,但发现它仅用于创建可在SwiftUI Text视图中使用的自定义类型,无法满足需求。当前代码中Text("\(item)")报错:No exact matches in call to instance method 'appendInterpolation'。

如何调整才能让OrderedSet只接受可用于Text视图的元素类型?以下是简化示例代码:

import SwiftUI
import OrderedCollections

struct ReusableListView<Element: Hashable>: View {
    
    @Binding var set: OrderedSet<Element>
    
    @State private var multiSelection: Set<Element> = []
    
    init(_ set: Binding<OrderedSet<Element>>) {
        self._set = set
    }
    
    var body: some View {
        Section {
            List(selection: $multiSelection) {
                ForEach(set, id: \.self) { item in
                    Text("\(item)")
                }
                .onDelete { indexSet in
                    set.elements.remove(atOffsets: indexSet)
                }
            }
        }
    }
}

@main
struct MyApp: App {
    
    @State private var setWithStrings: OrderedSet<String> = ["hello", "world"]
    @State private var setWithInts: OrderedSet<Int> = [1, 2, 3]
    
    var body: some Scene {
        
        WindowGroup {
            ReusableListView($setWithStrings)
            ReusableListView($setWithInts)
        }
    }
}

解决方案

自定义一个TextSupport协议,要求遵循该协议的类型提供一个可直接用于Text的字符串属性,然后让需要支持的基础类型(如String、Int)扩展遵循该协议,最后在组件的泛型约束中添加该协议即可。完整可运行代码如下:

import SwiftUI
import OrderedCollections

protocol TextSupport {
    var text: String { get }
}

extension String: TextSupport {
    var text: String { self }
}

extension Int: TextSupport {
    var text: String { self.formatted() }
}

struct ReusableListView<Element: Hashable & TextSupport>: View {
    
    @Binding var set: OrderedSet<Element>
    
    @State private var multiSelection: Set<Element> = []
    
    init(_ set: Binding<OrderedSet<Element>>) {
        self._set = set
    }
    
    var body: some View {
        Section {
            List(selection: $multiSelection) {
                ForEach(set, id: \.self) { item in
                    Text(item.text)
                }
                .onDelete { indexSet in
                    set.elements.remove(atOffsets: indexSet)
                }
            }
        }
    }
}

@main
struct MyApp: App {
    
    @State private var setWithStrings: OrderedSet<String> = ["hello", "world"]
    @State private var setWithInts: OrderedSet<Int> = [1, 2, 3]
    
    var body: some Scene {
        
        WindowGroup {
            ReusableListView($setWithStrings)
            ReusableListView($setWithInts)
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 09:35:32