如何传递一个闭包,该闭包返回一个符合Equatable的值到函数中

Jos*_*oid 1 arrays protocols swift

我正在尝试创建一个扩展,Array根据应用了闭包的项返回一个新的唯一项数组.

例如:如果我有一个Apple苹果具有属性名称和来源的数组,那么我将调用每个来源的一个Appleapple.uniqued(on: { $0.origin })

这是我到目前为止的代码:

extension Array where Element: Equatable {
    func uniqued(on extract: (Element) -> Equatable) { // A
        let elementsAndValues = map { (item: $0, extracted: extract($0)) } // 1

        var uniqueValues: [Element] = []
        var uniqueExtracts: [Equatable] = [] // A

        elementsAndValues.forEach { (item, extracted) in
            if !uniqueExtracts.contains(extracted) { // 3, B
                uniqueValues += [item]
                uniqueExtracts += [extracted]
            }
        }

        return uniqueValues
    }
}
Run Code Online (Sandbox Code Playgroud)

这应该如下工作:

  1. 创建一个元组数组,包含原始元素(item)和应用了闭包的元素(提取)
  2. 如果uniqueExtracts不包含该项,请添加该项并将该项添加到uniqueItems数组中.

我得到的错误是:

A)"协议'SomeProtocol'只能用作通用约束,因为它具有Self或相关类型要求"(两次)

B)"缺少参数标签"其中:'在通话中'

我正在使用最新版本的Xcode.任何建议都会有很多帮助.非常感谢.

tay*_*ift 5

您有多个问题混合在一起以创建您所看到的错误.你应该做的是使用通用.

extension Array
{
    func uniqued<T:Equatable>(on extract:(Array.Element) -> T) -> [Array.Element]
    {
        let elementsAndValues = self.map{ (item: $0, extracted: extract($0)) }

        var uniqueValues:[Element] = []
        var uniqueExtracts:[T] = []

        for (item, extracted) in elementsAndValues
        {
            if !uniqueExtracts.contains(extracted)
            {
                uniqueValues.append(item)
                uniqueExtracts.append(extracted)
            }
        }

        return uniqueValues
    }
}
Run Code Online (Sandbox Code Playgroud)

<T:Equatable>声明了一个泛型类型参数T符合Equatable.然后函数签名可以期望一个闭包,它返回一些T我们知道Equatable从尖括号中的类型约束符合的泛型类型.您还必须将每次出现更改Equatable为泛型参数T,因为Equatable它不是真实类型; 在这里看到我的答案.如果你这样做,代码应该编译.

您还应该更改一些其他内容:

  • 而不是使用elementsAndValues.forEach(:),使用for <pattern> in list {}循环.

  • 虽然这是有争议的,但在向数组添加一个元素时,您应该使用该Array().append(:)方法而不是+=连接.+=相反+,在这种情况下,这纯粹是为了传达意图.

  • 您没有为函数声明返回类型,因此编译器假定它返回Void,因此该return uniqueValues语句将导致编译器错误.添加一个-> [Array.Element]功能来解决这个问题.

  • where Element:Equatable作为对Array自身的约束是多余的.您正在使用键函数来确定均衡性,因此元素本身是否相等是无关紧要的.

  • 您可能希望使用一个Set或一些其他散列数据结构而不是uniqueExtracts数组.测试数组中的成员资格是一项O(n)操作.

  • @JoshParadroid这是一个建议,因为你的代码会编译,但是"Swifty"代码在重用闭包时只使用`forEach(:)`,例如,如果你想要在变异外部变量时想要迭代多个数组.否则使用`for`循环. (2认同)