34

在 Xcode 9 中的 Swift 4 的光泽项目之后

我收到以下错误,我不知道

闭包元组参数 '(key: _, value: _)' 不支持解构

代码:

extension Dictionary
{
    init(elements: [Element]) {
        self.init()
        for (key, value) in elements {
            self[key] = value
        }
    }

    func flatMap<KeyPrime, ValuePrime>(_ transform: (Key, Value) throws -> (KeyPrime, ValuePrime)?) rethrows -> [KeyPrime:ValuePrime] {
        return Dictionary<KeyPrime, ValuePrime>(elements: try flatMap({ (key, value) in
            return try transform(key, value)
        }))
    }
}

错误出现在这一点上try flatMap({ (key, value)in

4

4 回答 4

25

让我们从flatMap字典的定义开始,如下所示:

func flatMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

你看到transform闭包只接受一个类型的参数Element,其中Element只是typealias一个元组:

public typealias Element = (key: Key, value: Value)

所以闭包的第一个也是唯一的参数应该是两个元素(key类型Keyvalue类型Value)的元组。


现在,如果您查看您的代码(在 Swift 3 中编译),您会发现情况并非如此,您应该问为什么这在 Swift 3 中也可以工作。

try flatMap({ (key, value) in
    return try transform(key, value)
})

您的闭包需要 2 个参数而不是一个(key类型Keyvalue类型Value)。这在 Swift 3 中有效,这要归功于一个称为解构的功能,其中编译器会自动将 2 个元素的元组转换为 2 个参数。

但是这个特性很奇怪,很少使用并且大多数时候会产生意想不到的结果,所以它在 Swift 4 中被删除了。
编辑:正如 OOPer 所指出的,这个特性在 Swift 4 beta 中被暂时删除,但应该在之前重新添加最终版本出来了。

相反,你应该写:

try flatMap({ tupleArgument in
    return try transform(tupleArgument.key, tupleArgument.value)
})

你的flatMap功能变成:

func flatMap<KeyPrime, ValuePrime>(_ transform: (Key, Value) throws -> (KeyPrime, ValuePrime)?) rethrows -> [KeyPrime:ValuePrime] {
    return Dictionary<KeyPrime, ValuePrime>(elements: try flatMap({ element in
        return try transform(element.key, element.value)
    }))
}
于 2017-07-06T11:01:34.010 回答
7

这是 Swift 4 提案的副作用:

SE-0110 区分单元组和多参数函数类型

但是这个提案中包含的一些特性导致了一些回归,这在进化公告邮件列表的这篇文章中得到了解决:

[swift-evolution-announce] [核心团队] 解决 Swift 4 中的 SE-0110 可用性回归问题

因此,您可以期望在 Xcode 9 的未来 beta 或 GM 版本中,您的代码将再次编译良好。在此之前,您可以使用这种解决方法:

internal func flatMap<KeyPrime , ValuePrime>(_ transform: (Key, Value) throws -> (KeyPrime, ValuePrime)?) rethrows -> [KeyPrime : ValuePrime] {
    return Dictionary<KeyPrime,ValuePrime>(elements: try flatMap({ pair in
        let (key, value) = pair
        return try transform(key, value)
    }))
}

顺便说一句,在 Swift 4 中,Dictionary有一些新的初始化器,它们采用Sequence(Key, Value)对。例如:

初始化(uniqueKeysWithValues:S)

于 2017-07-06T11:01:45.133 回答
6

由于使用,我刚刚遇到了这个错误enumerated().map()

闭包元组参数不支持解构

我输入了代码:

["foo"].enumerated().map

然后按Enter3 次,直到 Xcode 自动完成关闭样板。

自动完成似乎有一个导致上述错误的错误。自动完成产生双括号((offset: Int, element: String))而不是单括号(offset: Int, element: String)

我手动修复它并能够继续:

// Xcode autocomplete suggests:
let fail = ["foo"].enumerated().map { ((offset: Int, element: String)) -> String in
    return "ERROR: Closure tuple parameter does not support destructuring"
}

// Works if you manually replace the "(( _ ))" with "( _ )"
let pass = ["foo"].enumerated().map { (offset: Int, element: String) -> String in
    return "works"
}

可能是使用 Xcode 10.0 beta (10L176w) 的结果

于 2018-07-19T01:52:18.937 回答
1

我正在使用 Xcode 11.1 和 Swift 5,并在使用enumerated().map(). 我认为这个例子稍微简化了一些事情,但总的来说,这对我来说是固定的。真正的错误是编译器无法推断返回值:

// Correct Syntax
let resultModels: [ResultModel] = array.enumerated().map { index, model in
  // code
}

// Results in the error Closure tuple does not support destructuring
let resultModels = array.enumerated().map { index, model in
  // code
}
于 2019-12-04T00:43:24.657 回答