some in Swift

swift 中有一个不透明类型的概念,在 SwiftUI 开发中经常看到的 var body: some View 正是基于这个概念。这篇文章来研究下 some 的作用。

看下面的代码

protocol Shape {
    func describe() -> String
}

struct Square: Shape {
    func describe() -> String {
        return "I'm Square"
    }
}

struct Circle: Shape {
    func describe() -> String {
        return "I'm circle"
    }
}


func makeShape() -> some Shape {
    return Circle()
}

let shape = makeShape()
print(shape.describe())

复制代码

上面代码定义一个 protocol ,并且有两个 struct 实现了该协议,some 的使用出现在 makeShape 函数的返回值中,这里使用 some 表示:该函数的返回值是实现了 protocol 协议的某一个类型,具体是什么类型不知道some 的「不透明类型」指的就是:没有明明白白告诉你具体是什么类型的,只是说明了这个类型和 Shape protocol 有关。

但是,makeShape 的返回值改成 Shape 仍然可以运行:

func makeShape() -> Shape {
    return Circle()
}
复制代码

someprotocol 有啥区别?

我们知道 protocol 中可以有 associatedtype ,基于上面的代码,引入 associatedtype 看看。

protocol Shape {
   
    associatedtype ColorType
    var color: ColorType { get }
    
    func describe() -> String
}


struct Square: Shape {
    var color: String
    typealias ColorType = String

    func describe() -> String {
        return "I'm Square"
    }
}

struct Circle: Shape {
    
    var color: Int
    typealias ColorType = Int

    func describe() -> String {
        return "I'm circle"
    }
}


func makeShape() -> some Shape {
    return Circle(color: 255)
}

let shape = makeShape()
print(shape.describe())
复制代码

现在 Shape 引入了 associatedtype,每个实现 Shape protocolstruct 都需要明确 ColorType 的具体类型。现在 makeShape 的返回值如果仍然是 Shape 就会报错:Protocol 'Shape' can only be used as a generic constraint because it has Self or associated type requirements。原因在于 swift 不知道返回值 Shapeassociatedtype 是什么类型。在引入 some 之后,swift 可以从 return 的类型推断出 associatedtypeInt 类型。

总结一下:为什么需要 some?因为 protocol 中有 associatedtype 时,使用 protocol 的地方无法确定 associatedtype 的类型,那么这个时候使用 some 修饰,表示:这个地方是一个实现了 protocol** 的类型,具体是什么类型尚未确定**。

最后,来理解 SwiftUI 中 some 的使用。

var body: some View {
    VStack(alignment: .leading) {
        Text("hello")
        Text("world")
    }
}
复制代码

这里,body 属性的具体类型为 VStack<TupleView<(Text, Text)>>,随着布局深入,那么类型就会越来越复杂。所以这里使用 some View 来代替,告诉 swift:body 是一个实现了 View protocol 的结构体,具体是什么类型不清楚,你可以在编译的时候通过返回值推断出来。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享