作为通用类型传递结构体并访问该通用类型的属性。

3

我正在开发一个Swift包,其中一个选项是传入一个泛型类型(Person),然后GenericStruct可以使用传入类型的属性。显然问题在于泛型类型T不知道究竟传入了什么类型。 有没有一种方法来定义在泛型类型T上访问属性的方式?

struct Person: Equatable {
    var name: String
    var height: Double
}

struct ContentView: View {
    @State private var james = Person(name: "James", height: 175.0)
    
    var body: some View {
        GenericStruct(person: $james)
    }
}

struct GenericStruct<T: Equatable>: View {
    @Binding var person: T
    
    var body: some View {
        Text(person.name)) // This line.
    }
}

我希望在传递给 GenericStruct 时,能够明确指定要访问 Person 上的哪个属性。该属性并不总是 name,它可以是在 Person 中定义的任何内容。例如:

GenericStruct(person: $james, use: Person.name)
1个回答

4
这不就是一个协议吗?
protocol NameProviding {
    var name: String { get }
}

struct GenericStruct<T: Equatable & NameProviding>: View { ... }

还有更微妙的问题吗?


最佳方法是传递一个字符串绑定:

struct GenericStruct: View {
    @Binding var text: String
    
    var body: some View {
        Text(text)) // This line.
    }
}

GenericStruct(text: $james.name)

但使用键路径是可能的。在这种情况下,只是有些笨拙且不太灵活:

// Should be the syntax, but I haven't double-checked it.
struct GenericStruct<T: Equatable>: View {
    @Binding var person: T
    var use: KeyPath<T, String>
    
    var body: some View {
        Text(person[keyPath: use]))
    }
}

GenericStruct(person: $james, use: \.name)

传入的类型可能是任何东西,它不一定包含“名称”。它可能类似于“Person(name:String、height:Double、age:Int)”,然后我希望能够在传入的值上访问“name”、“height”或“age”中的任何一个。当调用“GenericStruct”时,我想明确定义要访问哪个属性。 - Joe Scotto
你能举个调用代码的例子吗?我无法想象“调用GenericStruct”是什么意思。通常你不会“调用”body,所以感觉你的例子中还有更多内容。 - Rob Napier
GenericStruct(person: $james, use: Person.name) then GenericStruct would access .name on the passed in Person - Joe Scotto
我假设.name需要是一个字符串属性,对吗?(否则你无法在调用Text时使用它)。这是可行的,但只需传递一个字符串绑定更容易和更灵活:GenericStruct(string: $james.name) - Rob Napier
KeyPath 已经生效了,谢谢! - Joe Scotto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接