如何定义具有通用函数和一些视图作为返回类型的协议

时间:2021-07-01 18:01:10

标签: swift swiftui

我想创建一个具有以下功能的协议

@ViewBuilder
func navigate<T: View>(content: () -> T) -> some View {
    switch self{
    case .list:
        NavigationLink(destination: Text("Test")){ content() }
    default:
        EmptyView()
    }
}

这是我的尝试,但不起作用

protocol Test {
    associatedtype Result: View

    func navigate<T: View>(content: () -> T) -> Result
}

2 个答案:

答案 0 :(得分:1)

Opaque Result Types 提案的 Associated Type Inference 部分明确不允许这样做。来自提案:

<块引用>

关联类型推断只能为非泛型需求推断出不透明的结果类型,因为不透明类型是由函数自己的泛型参数参数化的。例如,在:

protocol P {
 associatedtype A: P
 func foo<T: P>(x: T) -> A
}

struct Foo: P {
 func foo<T: P>(x: T) -> some P {
   return x
 }
}

没有单一的底层类型可以推断 A,因为 foo 的返回类型可以随 T 改变。

为了使您的问题更具体,为了符合 Test,必须只有一种类型可以分配给 Result。但是,您的返回类型是通用的,因此它取决于传递的内容。 navigate 的实际(非不透明)返回​​类型是:

_ConditionalContent<NavigationLink<T, Text>, EmptyView>

但是 T 是一个类型参数,会根据 navigate 的调用方式而变化。所以没有一种类型可以分配给 Result

您需要可以返回单个非参数化类型的东西。对于您给出的示例,可能是 AnyView,这很烦人。

也就是说,你在这里写的东西感觉起来不像是一个协议。它看起来很像一个函数。我想了很多关于 navigate 可以写多少种不同的方式。如果每个人都以相同的方式实现它,那只是一个功能。 (如果您再举一个符合类型的示例,可能有助于设计更好的方法。)

答案 1 :(得分:0)

您可以在目的地调用它的地方执行此操作。

extension View {
     func navigate< Destination: View, Label: View>(content: Label) -> some View   {
          NavigationLink(destination: Destination) { content.    }
     }
}

问题是您无法在方法中找到调用者,因为您正在扩展协议。