SwiftUI:为什么 ModifiedContent 符合 `some View` 函数返回类型?

sug*_*ron 0 swift swiftui

// it compiles without any problems, regardless ModifiedContent is not a View
func modify(with viewModifier: some ViewModifier) -> some View {
    let content: ModifiedContent<Self, some ViewModifier> = modifier(viewModifier)
    return content
}
Run Code Online (Sandbox Code Playgroud)

但如果我们以通用方式编写相同的内容,我们会收到预期的错误消息

func modify<V>(with viewModifier: some ViewModifier) -> V where V : View {
    let content: ModifiedContent<Self, some ViewModifier> = modifier(viewModifier)
    return content // error: Cannot convert return expression of type 
                   //       'ModifiedContent<Self, some ViewModifier>' to return type 'V'
}
Run Code Online (Sandbox Code Playgroud)

rob*_*off 7

这是您的第一份工作声明:

\n
\n
func modify(with viewModifier: some ViewModifier) -> some View\n
Run Code Online (Sandbox Code Playgroud)\n
\n

some在该函数声明中使用了该关键字两次。重要的是要理解这在这两种用途中some意味着不同的事情

\n

在第一次使用 ( viewModifier: some ViewModifier) 中,some关键字是 \xe2\x80\x9c 语法糖\xe2\x80\x9d,用于隐式、未命名的泛型参数。我们可以通过将其替换为显式的、命名的泛型参数来对它的使用进行去糖化some,如下所示:

\n
// Replace `some` in parameter position with an explicit generic parameter:\nfunc modify<VM: ViewModifier>(with viewModifier: VM) -> some View\n
Run Code Online (Sandbox Code Playgroud)\n

当您调用该modify方法时,您作为调用者选择一个实际类型来替换VM参数。所以你可以modify多次调用,VM每次都用不同的类型来替换。唯一的限制是替换类型必须始终符合ViewModifier协议。

\n

some第一个函数声明中的第二次使用(in -> some View) 具有不同的含义。这意味着函数将返回一个类型符合 的值View,但具体类型由函数体选择。作为函数调用者,您不选择类型。

\n

总结一下差异:

\n
    \n
  • some参数位置关键字

    \n
      \n
    • 表示隐式的、未命名的泛型类型参数;
    • \n
    • 可以在不更改函数体的情况下将其脱糖为显式的、命名的通用参数;
    • \n
    • 被函数调用者选择的类型替换。
    • \n
    \n
  • \n
  • some返回类型位置的关键字

    \n
      \n
    • 表示已知符合协议的类型;
    • \n
    • 是函数体选择的类型。
    • \n
    \n
  • \n
\n

现在让我们看看第二个损坏的函数声明:

\n
\n
func modify<V>(with viewModifier: some ViewModifier) -> V where V : View\n
Run Code Online (Sandbox Code Playgroud)\n
\n

这与您的第一个函数声明类似,只是您已将some返回类型位置替换为泛型参数V

\n

问题是这些含义并不相同。正如我上面所解释的,返回类型some View意味着函数体选择实际类型,但泛型参数始终由函数的调用者选择。

\n

这就是为什么当您的函数尝试执行此操作时会出现错误return content。无法保证具有contenttype V。您的函数对类型知之甚少V(您只知道它符合View),以至于该函数甚至无法创建类型值V(因为View协议没有任何init要求)。

\n

您对第一个工作函数声明也有这样的评论:

\n
\n
// it compiles without any problems, regardless ModifiedContent is not a View\n
Run Code Online (Sandbox Code Playgroud)\n
\n

我假设您modify(withViewModifier:)extension View. 这意味着Self符合View,所以ModifiedContent<Self, some ViewModifier>符合View

\n

  • 当“内容符合 View 并且修饰符符合 ViewModifier”时,ModifiedContent 有条件地符合“View”,如文档页面底部所述 (2认同)