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