【问题标题】:How to mutate structs in Swift using map?如何使用 map 在 Swift 中改变结构?
【发布时间】:2021-11-07 02:18:46
【问题描述】:

我定义了以下结构。

struct Person {

    var firstName :String
    var lastName :String
    var active :Bool
}

我创建了一个 Person 集合,如下所示:

var persons :[Person] = []

for var i = 1; i<=10; i++ {

    var person = Person(firstName: "John \(i)", lastName: "Doe \(i)", active: true)
    persons.append(person)
}

现在我正在尝试使用以下代码将 active 属性更改为 false:

let inActionPersons = persons.map { (var p) in

    p.active = false
    return p
}

但我收到以下错误:

Cannot invoke map with an argument list of type @noescape (Person) throws

有什么想法吗?

解决方案:

看起来 Swift 有时无法推断类型,这有点蹩脚!这是解决方案:

let a = persons.map { (var p) -> Person in

        p.active = false
        return p
}

这不起作用:

let a = persons.map { p in

        var p1 = p
        p1.active = false
        return p1
}

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    Swift 编译器在两种情况下推断返回值 自动闭包类型:

    • “单表达式闭包”中, 即闭包体 仅由单个表达式组成(有或没有显式 闭包参数)。
    • 如果类型可以从调用上下文中推断出来。

    这些都不适用于

    let inActionPersons = persons.map { (var p) in
        p.active = false
        return p
    }
    

    let a = persons.map { p in
            var p1 = p
            p1.active = false
            return p1
    }
    

    这就是为什么 您必须明确指定返回类型,如 Kametrixom's answer

    单表达式闭包示例:

    let inActionPersons = persons.map { p in
        Person(firstName: p.firstName, lastName: p.lastName, active: false)
    }
    

    它也可以用(var p) in(p : Person) in 编译,所以这与是否给出闭包参数无关 是否在括号中明确显示。

    这是一个从调用推断类型的示例 上下文:

    let a : [Person] = persons.map { p in
        var p1 = p
        p1.active = false
        return p1
    }
    

    map()的结果必须是[Person]数组,所以map需要 Person -&gt; Person 类型的闭包,编译器推断 自动返回类型Person

    有关更多信息,请参阅“从上下文推断类型”和“从单表达式闭包隐式返回” "Closures" Swift 书中的章节。

    【讨论】:

    • 你有那些隐式类型推断规则的链接吗?
    • @Kametrixom:在developer.apple.com/library/ios/documentation/Swift/Conceptual/… 中有“从上下文推断类型”和“从单表达式闭包隐式返回”部分。它没有明确说明这些是推断类型的 only 情况,但这就是我通过尝试和错误得出的结论。 – 但是从示例中可以看出,它不依赖于 "... 使用括号作为参数..."
    • 是的,虽然这看起来很奇怪,但这有效:persons.map{ return $0 },但persons.map{ print(""); return $0 } 无效。我猜它要么是一个错误,要么只是尚不支持,因为这绝对可以工作
    • @Kametrixom:显然return &lt;someExpression&gt; 也被视为单表达式闭包。
    • 没错,但这条规则并不是真正的官方规则,类型系统应该真的能够推断类型,我很惊讶它不能,因为 Swift 的类型推断通常非常强大
    【解决方案2】:

    当使用方括号作为参数以使var 起作用时,您还必须输入返回类型:

    let inActionPersons = persons.map { (var p) -> Person in
    
        p.active = false
        return p
    }
    

    【讨论】:

    • 即使您不使用方括号并将 p 移动到新变量 p1 中,它也需要明确指示返回类型。检查原始帖子的更新。
    • @johndoe 是的,我刚才也意识到了,我认为这是一个错误,因为persons.map{ return $0 } 有效,但persons.map{ print(""); return $0 } 无效
    • 可能是语言中的错误!希望这可以在以后的版本中修复!
    • 另外,当您使用 $0 语法时,如何将 $0 声明为 var 而不是 let。
    • @johndoe 不能将 $0 声明为常量,因为声明是隐式的
    【解决方案3】:

    斯威夫特 5

    无论如何,从 Swift 5 开始,已接受的答案不再有效。闭包不再有关键字参数,这意味着迭代的每个元素都必须保持不变。因此,要使用map 改变结构,必须在每次迭代中初始化新元素:

    let activePersons = persons.map { (p) -> Person in
        return Person(firstName: p.firstName, lastName: p.lastName, active: true)
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-10
      • 2022-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-28
      • 2011-11-04
      • 2012-04-09
      • 2013-09-27
      相关资源
      最近更新 更多