讨论下 Swift 编译器在对待 Opaque Types 下的行为

2023-02-23 11:41:53 +08:00
 FaiChou

前提条件:

protocol MobileOS {
    associatedtype Version
    var version: Version { get }
    init(version: Version)
}
struct iOS: MobileOS {
    var version: Float
}
struct Android: MobileOS {
    var version: String
}

于是写一个函数:

func buildOS() -> MobileOS {
  return iOS(version: 16.1)
}

这样编译器会报错, 因为它无法推断出 associatedtype, 但是在 MobleOS 前面加上 some, 它就不会报错, 所以 some 是让编译器忽略类型推断, 只需要返回的类型继承 MobileOS 即可?

那接着来:

func buildOS() -> some MobileOS {
   let isEven = Int.random(in: 0...10) % 2 == 0
   return isEven ? iOS(version: 16.1) : Android(version: "Pie")
}

这样编译器又报错了, 如果将 Android(version: "Pie") 改成 iOS(version: 16.2) 就不会报错. 所以编译器也是会推断返回值类型? 必须要返回相同的类型?

在 SwiftUI 中有很多这样的例子, 而且如果想返回多个不同类型, 需要加一个 @ViewBuilder, 这样编译器又行了..???

类型和协议是两个不同的派系, 类型可以符合某些协议, 函数或者计算属性也可以用协议来替代类型作为返回. 基于以上, 为什么不让编译器宽泛一点, 却引入一个 some 来增加程序员的理解?

能有上述问题是因为我遇到了下面这个错误, 代码是按照官方例子中的 demo: https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit

struct PageView<Page: View>: View {
  var page: [Page]
  // body ..
}
struct Page1: View {
  var body: some View {
    Color.red
  }
}
struct Page2: View {
  var body: some View {
    Color.red
  }
}
struct ContentView: View {
  var body: some View {
    PageView(page: [Page1(), Page2()])
  }
}

这样编译器会直接报错, 并且错误原因也不给. 但当我将数组只放一个数据时候, 编译器就给通过了 PageView(page: [Page1()]), 如果想要数组多个数据, 需要用 AnyView 包裹一下每个 Page.

1108 次点击
所在节点    Swift
4 条回复
Vancion
2023-02-23 11:46:43 +08:00
WildCat
2023-02-23 11:49:59 +08:00
9 年 Swift 经验开发者路过。
即使有了 some 我也个人也不会这么用 protocol 了 associated type 。这个语言设计的太过糟糕。
建议 MobileOS 替换为 enum

```swift
enum MobileOS {
case iOS(version: Float)
case Android(version: String)
}
```
FaiChou
2023-02-23 11:58:02 +08:00
@WildCat MobileOS 只是个例子, 主要是我最后的这个 PageView 的问题, 你帮忙看下, 除了 AnyView 包裹还有什么方法可以解决?
weeei
2023-04-20 08:02:15 +08:00
PageView 的例子,数组必须是同一类型,这是语言规则限定的,不用 AnyView 就需要定义空协议或字类化做类型限定。

MobileOS 的例子,some 的作用是类型擦除,我的理解是语法糖,在编译期间自动推导类型,如果是运行期间才确定类型就会报错,这个算是 some 的特性。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/918487

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX