【问题标题】:Closure tuple does not support destructuring in Xcode 9 Swift 4闭包元组不支持 Xcode 9 Swift 4 中的解构
【发布时间】:2017-07-06 10:10:02
【问题描述】:

在 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

【问题讨论】:

  • Dictionary.init(elements:) 在 Swift 标准库中找不到。你自己定义的?
  • 是的,我正在更新答案
  • 我已经更新了答案

标签: ios swift swift4 xcode9-beta


【解决方案1】:

让我们从字典中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 个参数而不是 1 个参数(Key 类型的 keyValue 类型的 value)。这在 Swift 3 中有效,这要归功于一个名为 destructuring 的功能,其中编译器会自动将 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)
    }))
}

【讨论】:

  • 感谢您的解释。这是我试图使其与 swift4 兼容的第三方库。
【解决方案2】:

这是 Swift 4 提案的副作用:

SE-0110 Distinguish between single-tuple and multiple-argument function types.

但是该提案中包含的一些功能导致了一些回归,这在evolution-announce mailing list的这篇帖子中得到了解决:

[swift-evolution-announce] [Core team] Addressing the SE-0110 usability regression in Swift 4

因此,您可以期望在 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) 对。例如:

init(uniqueKeysWithValues: S)

【讨论】:

    【解决方案3】:

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

    闭包元组参数不支持解构

    我输入了代码:

    ["foo"].enumerated().map
    

    然后按 Enter 3 次,直到 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) 的结果

    【讨论】:

    • 我确认了这一点,但修复并不能解决所有问题。考虑一下这个:let allLocales: [(String, String)] = Locale.isoRegionCodes.map({ ($0, Locale.current.localizedString(forRegionCode: $0) ?? "Unknown") }).sorted {((c0: String, r0: String), (c1: String, r1: String)) -&gt; Bool in return r0 &lt; r1 }.sorted { $0.1 &lt; $1.1 } 有什么问题@ 选项一可能想知道。假设我想省略c1, c2,将它们替换为`_`。看不出有什么办法。
    • @PaulB 至少似乎对错误 Closure tuple parameter does not support destructuring 有意义。这意味着您(当前)不能使用解构的元组作为闭包的参数。希望将来会添加到该语言中。切换到 结构化 元组参数,它工作正常:.sorted { (locale0, locale1) -&gt; Bool in。我的代码示例中的参数不是元组,但 Xcode 自动完成通过额外的 ( ) 将它们呈现出来。
    • 是的,@pkamb,就是这样。可以使用任何您想要的参数标签,但是不支持“就地”分解元组(还没有?),因为相应的错误消息指出。所以令人惊讶的是,在某些情况下,您实际上可以以某种方式解构一个元组(或元组?)并编写如下内容:let pass = ["foo"].enumerated().map { (offset: Int, _: String) -&gt; String in return "works" }
    【解决方案4】:

    我正在使用 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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-02
      • 2019-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-06
      相关资源
      最近更新 更多