V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
FaiChou
V2EX  ›  Swift

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

  •  
  •   FaiChou ·
    FaiChou · 2023-02-23 11:41:53 +08:00 · 930 次点击
    这是一个创建于 422 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前提条件:

    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.

    4 条回复    2023-04-20 08:02:15 +08:00
    WildCat
        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)
    }
    ```
    FaiChou
        3
    FaiChou  
    OP
       2023-02-23 11:58:02 +08:00
    @WildCat MobileOS 只是个例子, 主要是我最后的这个 PageView 的问题, 你帮忙看下, 除了 AnyView 包裹还有什么方法可以解决?
    weeei
        4
    weeei  
       2023-04-20 08:02:15 +08:00
    PageView 的例子,数组必须是同一类型,这是语言规则限定的,不用 AnyView 就需要定义空协议或字类化做类型限定。

    MobileOS 的例子,some 的作用是类型擦除,我的理解是语法糖,在编译期间自动推导类型,如果是运行期间才确定类型就会报错,这个算是 some 的特性。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2932 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 08:54 · PVG 16:54 · LAX 01:54 · JFK 04:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.