SwiftUI传递带泛型参数的函数时ChildView的参数如何定义
报错原因
你原来的两种写法无法编译的核心原因是:Swift不允许直接在结构体的属性上声明泛型参数,泛型参数需要定义在结构体本身的声明层级,或者通过类型擦除抹掉具体类型约束。
方案1:给ChildView添加泛型参数(推荐,编译时类型安全)
如果单个ChildView实例只会返回固定一种类型的GeneralAnswer(比如这个ChildView是数字输入页就只传Int,文本输入页就只传String),直接把泛型参数声明在ChildView结构体上即可:
// 正确的ChildView定义 struct ChildView<T>: View { var okClicked: (GeneralAnswer<T>) -> Void var body: some View { // 内部调用示例 Button("提交") { // 传入对应类型的参数即可,比如Int类型 okClicked(GeneralAnswer(value: 2024)) // 如果是String类型就写 okClicked(GeneralAnswer(value: "测试结果")) } } }
ParentView的原有代码不需要做任何修改,Swift会自动根据使用场景推导T的具体类型。
方案2:类型擦除支持多类型返回
如果同一个ChildView实例需要返回多种不同类型的GeneralAnswer,可以用Swift 5.7+提供的any关键字做类型擦除:
- 先给GeneralAnswer添加公共协议:
protocol GeneralAnswerProtocol {} extension GeneralAnswer: GeneralAnswerProtocol {}
- 定义ChildView:
struct ChildView: View { var okClicked: (any GeneralAnswerProtocol) -> Void var body: some View { VStack { Button("提交数字") { okClicked(GeneralAnswer(value: 100)) } Button("提交文本") { okClicked(GeneralAnswer(value: "提交的文本内容")) } } } }
- 对应修改ParentView的okClicked实现:
struct ParentView: View { func okClicked(userAnswer: any GeneralAnswerProtocol) { // 内部按需做类型判断即可 if let intRes = userAnswer as? GeneralAnswer<Int> { print("收到数字:\(intRes.value)") } else if let stringRes = userAnswer as? GeneralAnswer<String> { print("收到文本:\(stringRes.value)") } } var body: some View { ChildView(okClicked: okClicked) } }
内容的提问来源于stack exchange,提问作者DevB2F
相关产品推荐
相关产品推荐

