选择Array扩展的类型



我试图扩展Array.contains函数以允许可选参数并在参数为nil时返回false。我是这样开始的:

extension Array {
func contains(_ element: Element?) -> Bool {
if let element = element {
return self.contains(element)
} else {
return false
}
}
}

当参数为nil时,调用代码正确地找到我的函数版本。然而,这个函数中的self.contains并不调用原始版本——它调用自己并创建一个无限循环。有没有办法让self.contains线调用原来的函数?

接下来,我尝试用不同的实现替换self.contains,但我想不出任何不需要限制扩展到Element: Equatable的东西,像这样:

extension Array where Element: Equatable {
func contains(_ element: Element?) -> Bool {
if let element = element {
return (self.firstIindex(of: element) != nil)
} else {
return false
}
}
}

然而,这使得函数不可用于元素类型,如UIButton, Dictionary和其他我需要使用它的东西。原始的contains函数如何为这些类型做到这一点?(我搜索了,找不到它的源代码)

接下来,我删除了约束并更改了方法签名,以消除扩展函数和原始函数之间的歧义:
extension Array {
func contains(optional element: Element?) -> Bool {
if let element = optional {
return self.contains(element)
} else {
return false
}
}
}

但是当我更改方法签名时,编译器错误告诉我self.contains行现在要求Element符合Equatable。为什么原始函数不受此限制,而签名略有不同的函数却需要此限制?

我觉得这应该是微不足道的,但我花了几个小时,找不到一个工作的设置。谁能告诉我一个解决办法?

在看到@Sweeper关于UIButton和Dictionary相等的评论后,我再次尝试使用该约束。我之前看到过uibutton数组的错误,但这次没有,所以那些一定是被别的东西触发的。然而,我所认为的字典的错误实际上只是普通的结构。我使用这个答案使我的结构符合Equatable,现在一切都按预期工作。

实际上,添加了Equatable约束后,无限循环不再发生,因此我可以回到函数的第一个版本:

extension Array where Element: Equatable {
func contains(_ element: Element?) -> Bool {
if let element = element {
return self.contains(element)
} else {
return false
}
}
}

显然有一个版本的contains()没有等价约束,这是我之前使用结构体时调用的,以及我的自定义函数用self.contains()调用的。总之,这些是我们学到的经验教训:

  1. 当创建本机函数的变体时,添加与原始函数相同的类型约束。

  2. 使自定义结构符合Equatable,以便于集合的使用。

最新更新