【问题标题】:Cannot modify my array - Cannot use mutating member on immutable value: function call returns immutable value无法修改我的数组 - 无法对不可变值使用变异成员:函数调用返回不可变值
【发布时间】:2021-05-03 10:22:48
【问题描述】:

我知道我做错了什么,但我不知道是什么..

我只想在这里添加一些pet 到我的Array<Pet>

我在这里做错了什么?

错误是

不能对不可变值使用变异成员:函数调用返回不可变值

import UIKit

struct Person {
    let id = UUID()
    let name: String
    var pets: [String]
}

final class City {
    let people = [Person]()
    
    func addPetFor(id: UUID, newPets: [String]) {
        self.people.findPerson(by: id).pets.append(contentsOf: newPets) //<-- error Cannot use mutating member on immutable value: function call returns immutable value
    }
}

extension Array where Element == Person {
    func findPerson(by id: UUID) -> Person {
        let foundPerson = self.first { person in
            person.id == id
        }
        return foundPerson!
    }
}

【问题讨论】:

    标签: arrays swift


    【解决方案1】:

    结构具有值语义。当您将它们传递/分配给事物时,它们会被复制,除非它是var,否则您不能改变它们。

    返回值不是vars,您不能更改返回值。可以先放到var变量中,再追加到pets

    var person = self.people.findPerson(by: id)
    person.pets.append(contentsOf: newPets)
    

    这会使编译器错误消失,但person 这里是返回值的副本,因此您在此处的修改实际上不会更改self.people 数组中的内容。 self.people 首先被声明为 let 常量,所以你最好也改变它:

    var people = [Person]()
    

    一种方法是让findPerson 返回找到的人的索引:

    extension Array where Element == Person {
        func findPerson(by id: UUID) -> Int {
            let foundPerson = self.firstIndex { person in
                person.id == id
            }
            return foundPerson!
        }
    }
    

    这样,你可以做到:

    let index = self.people.findPerson(by: id)
    self.people[index].pets.append(contentsOf: newPets)
    

    注意我是如何直接在self.people 上做事的,而不是通过另一个变量。 addPetFor 也需要标记为mutating。

    另一种方法是让findPerson 进行闭包,然后在该闭包中写下你想对找到的人做什么:

    extension Array where Element == Person {
        mutating func findPerson(by id: UUID, andDo block: (inout Person) -> Void) -> Int {
            let index = self.firstIndex { person in
                person.id == id
            }
            block(&self[index!])
        }
    }
    

    注意findPerson 现在如何标记为mutating,因为它现在改变了数组 (self)。 self[index] 由inout 传递,有点像“通过引用”。

    那么你可以这样做:

    self.people.findPerson(by: id) {
        $0.pets.append(contentsOf: newPets)
    }
    

    【讨论】:

      【解决方案2】:

      正如错误告诉您的那样,您的 findPerson 方法正在返回一个不可变结构,因此您无法对其进行编辑。

      有几个解决方案——下面的代码示例中包含两个:

      final class City {
          var people = [Person]()
          
          func addPetFor(id: UUID, newPets: [String]) {
              guard let index = self.people.firstIndex(where: { $0.id == id }) else {
                  assertionFailure("Not found")
                  return
              }
              self.people[index].pets.append(contentsOf: newPets)
          }
          
          func addPetFor2(id: UUID, newPets: [String]) {
              self.people = self.people.map {
                  if $0.id == id {
                      var personCopy = $0
                      personCopy.pets.append(contentsOf: newPets)
                      return personCopy
                  } else {
                      return $0
                  }
              }
          }
      }
      

      在这两种情况下,代码都引用了Person 在people 数组中的所属位置,因此可以对其进行修改。请注意,people 也必须是 var,而不是 let,原因相同——它必须是可变的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多