
前提条件:
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.
1 Vancion 2023-02-23 11:46:43 +08:00 |
2 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) } ``` |
3 ethusdt OP @WildCat MobileOS 只是个例子, 主要是我最后的这个 PageView 的问题, 你帮忙看下, 除了 AnyView 包裹还有什么方法可以解决? |
4 weeei 2023-04-20 08:02:15 +08:00 PageView 的例子,数组必须是同一类型,这是语言规则限定的,不用 AnyView 就需要定义空协议或字类化做类型限定。 MobileOS 的例子,some 的作用是类型擦除,我的理解是语法糖,在编译期间自动推导类型,如果是运行期间才确定类型就会报错,这个算是 some 的特性。 |