Swift 5.7 中的 any 和 some (译)

原文地址

由于 anysome 都适用于协议,因此我想在这篇博文中将它们放在一起比较以便更好地解说它们处理别离处理了什么问题,以及在什么情况下运用Swift anyswift是什么组织缩写some 或其他的。

了解 any 和 some 处理的问题

为了解说 any 处理的问题,咱们能够经过一个列子来了解这两个关键字。下面是一个Pizza模型的协议:

protocol Pizza {
    var size: Int { get }
    var name: String { get }
}

Swift 5.6,你或许会写下面的这种办法,来接收一个Pizza

func receivePizza(_ pizza: Pizza) {
    print("Omnomnom, that's a nice (pizza.name)")
}

当这个函数被调用时,receivePizza 函数接收一个所谓的披萨协议类型,咱们能够了解为一个披萨盒子。为了知道这个披萨称号,必须翻开这个盒子,也便是获取完成P泛型编程izza协议的详细目标,然后获取称号。这意味着 Pizza 几乎没有编译时优化,这使得 receivePizza 办法调用的开销比咱们想要的更大。

别的下面的函数,看起来好像是相同的

func receivePizza<T: Pizza>(_ pizza: T) {
    print("Omnomnom, that's a nice (pizza.name)")
}

不过,这里有一个很首要差异。Swift P泛型方法的定义和使用izzaswift是什么意思啊 协议在这里没有用作参数类型。它被用作泛型swift是什么组织缩写 T 的束泛型通配符缚。这就使得编译器将能够在编译时解析 T 的类型,使得 receivePizza 接受到的是一个详细化的类型。

由于上面这两种办法差异并不是swifterswift是什么清楚,所以 Swift 团队引入了 any 关键字。此关键字不增加任何新功能。它迫使咱们清楚地传达泛型通配符“这是一种存swifter在主义”:(有点拗口,也不是很好了解,我就把他了解成这么类型swift语言的一个东西)

// 上面的第一种写法,增加一个any关键字
func receivePizza(_ pizza: any Pizza) {
    print("Omnomnom, that's a nice (pizza.name)")
}

运用泛型T的示例不需求 any 关键字,由于 Pizza 被用作束缚而不是存在类型。

现在咱们对 any 有了更清晰的了解,继续让咱们研究一下 some

泛型的作用 Swift 中,许多开发人员都写如下代码:

let someCollection: Collection

咱们会遇到编译器过错,告知咱们 Collection 有 Self 或相关的类型要求。在 Swift 5.1 中,咱们能够告知编译器任何访问 someCollection 的人都不应该关怀这些。他们泛型的作用应该只需求知道这个东西契合 Collection 协议 ,仅此而已。

这种机制关于使 SwiftUI 的 View 协议至关重要。

但也有缺点,那便是在运用somSwiftUIe Cole泛型的作用lction的时候,无法知道其间的相关类型是什么。

可是,并非一切协议都有相关的相关类型。再次考虑下面这个receivePizza版别:

func receivePizza<T: Pizza>(_ pizza: T) {
    print("Omnomnom, that's a nice (pizza.name)")
}

咱们定义了一个通用的 T 来答应编译器针对给定swift国际结算系统的详细类型的 Pizza 进行优化。 some 关键字还答应编译器在编译时知道 some 目标的底层实践类型是什么;它仅仅对咱们躲藏。这正是 &泛型list和普通list有什么区别lt;T: Pizza> 所做泛型list和普通list有什么区别的。咱们经过 T 这个类型访问也只能访SwiftUI问到 Pizza 协议所公开的内容。这意味着咱们能够重写 receivePizza<T: Pizza>(_:) 如下:

func receivePizza(_ pizza: some Pizza) {
    print("Omnomnom, that's a nice (pizza.name)")
}

咱们不再需求 T ,也便是咱们不需求创立一个类型来代表咱们的 Pizza。咱们能swift国际结算系统够说“这个函数需求some Pizza”而不是“这个函数需求一些咱们称之为 T 的Pizza”。这两种写法是等价的。

挑选 some 仍是 any

其实当咱们了解了some 和 any, 就会知道这不选其间一个的问题,他们Swift都处理自己的问题的。

一般来说,咱们要尽或许的运用 some 或许泛型,就拿咱们的 Pizza 来说,如果运用any, 就泛型通配符好比咱们在运swift代码行时也会是接收到一个Pizza类型的盒子,详细是什么Pizza, 还需求咱们再swift是什么意思啊翻开盒子,可是some 或许泛泛型的作用型,就会给咱们一个实践的swift国际结算系统Pizza类型了。

实践

让咱们再举一个例子来阐明这一点,这个例子在很大程度上学习了我对泛型list和普通list有什么区别首要相关泛型的优点类型的解说。

class MusicPlayer {
    var playlist: any Collection<String> = []
    func play(_ playlist: some Collection<String>) {
        self.playlist = playlist
    }
}

在这段代码中,我运用了 some Col泛型方法lection<String> 而不是编写 func play<T:swift代码 Collection<String>>(_ playlist: T) ,由于泛型只在这一个当地运用。

我的 var playlistany Collection<String> 而不是 some Collection<String> 有两个原因:

  1. 无法保证编译器将为play办法推导的详细Colection与为var playlist推导的详细Colection相匹配;这意味着它们或许不相同。

  2. 编译器首要无法推断var playlist:some Collection<String>(尝试一下,你会得到一个编译器过错)

咱们能够用下面的写法来防止运用 any :

class MusicPlayer<T: Collection<String>> {
    var playlist: T = []
    func play(_ playlist: T) {
        self.playlist = playlist
    }
}

可是这样就会强制咱们的 T 为同一类型,比如说咱们在运用时 T 是Array,泛型list和普通list有什么区别 那咱们在play办法中就不能在传入其他的Collec泛型通配符tion类型,比如说Set。可是前面的那种写法是能够的。

总结

虽然 some 和 any 听起来很复杂(事实上的确如此),但它们也是 Swift 5.7 中非常强大和重要的部分。了解他们是很有必要的,由于这泛型方法能够协助咱们更好地了解 Swift 怎么处理泛型和协议。

评论

发表回复