1

mutating func即使在方法中使用关键字,我也无法修改我的模型类变量?

所以基本上我已经用一种非常简单的方式解决了我的问题,我有一个Car有 3 个变量的类idstartmodelNo

之后初始化一个空的 Car 模型数组,然后我想展示 10 辆汽车,创建一个循环的范围来迭代1...10,初始化 Car 模型类并将其附加到原始汽车数组。

检查前 5 辆汽车 id 为 0,最后 5 辆汽车 id 为 1

我想要一个过滤器,其中相同 id 的最后一辆车将启动,所以我创建了一个过滤并修改 start 变量但无法修改它的方法。你能帮我做错什么吗?

请查看我的完整代码并将其复制粘贴到操场上。

struct Car {
    var id = 0
    var start = false
    var modelNo: String

    init(start: Bool, id: Int, model: String) {
        self.start = start
        self.id = id
        self.modelNo = model
    }

    mutating func startCar(status: Bool) {
        start = status
    }
}

var arrCars:[Car] = [Car]()

for i in 1...10 {
    let md = Car(start: false, id: i <= 5 ? 0 : 1, model: "Model\(i)")
    arrCars.append(md)
}

private func filtered() {
    for item in arrCars {
        let filteredItems = arrCars.filter { $0.id == item.id }
        if filteredItems.count > 0 {
            if var lastItem = filteredItems.last {
                print("Will start \(lastItem.modelNo)")
                lastItem.startCar(status: true)
            }
        }
    }

    let cars = arrCars.filter { (car) -> Bool in
        car.start == true
    }

    print(cars.count)
}

filtered()

任何帮助将不胜感激。

4

3 回答 3

9

在结构上创建mutating函数不会改变结构的值语义。一旦结构实例发生变异,就会生成一个副本。

你说:

if var lastItem = filteredItems.last {
    print("Will start \(lastItem.modelNo)")
    lastItem.startCar(status: true)
}

因此,lastItem包含您将要启动的汽车的实例。在幕后,这是 in 中汽车filteredItems的同一个实例,也是 in 中的同一个实例arrCars。但是,一旦您对Carin进行了变异lastItem,就会制作一个副本,因此lastItem 不再具有与 in 相同的实例arrCarsfilteredItems并且arrCars仍然包含原始的、未更改的Car实例。

您可以更改Car为 aclass而不是 a struct,以便它具有引用语义来获得您想要的行为。

另一种选择是就地修改实例;类似的东西arrCars[0].startCar(status: true)。为此,您需要获取一个数组,其中包含您要启动的汽车的索引,而不是汽车本身:

private func filtered() {
    for item in arrCars {
        let matchingIndices = arrCars.enumerated().compactMap { (index,car) in
            return car.id == item.id ? index:nil
        }
        if matchingIndices.count > 0 {
            if let lastIndex = matchingIndices.last {
                print("Will start \(arrCars[lastIndex].modelNo)")
                arrCars[lastIndex].startCar(status: true)
            }
        }
    }

    let cars = arrCars.filter { (car) -> Bool in
        car.start == true
    }

    print(cars.count)
}

但是,在模型对象需要可变性或有状态的情况下,结构可能不适合。

于 2018-09-25T11:38:03.207 回答
4

到目前为止,您得到的答案并没有错,但它们似乎有点令人困惑。让我们更简单地看一下。问题是这一行:

if var lastItem = filteredItems.last

这会产生一个 Car as lastItem。但它. _ _filteredItems

那是因为 struct 是一个值类型。赋值复制结构。因此,你所做的对lastItem坐在里面的东西没有影响filteredItems

所以,你在改变一个结构时没有任何问题。你变异lastItem得很好!问题是lastItemCar 与里面的任何 Car 都不是同一个对象filteredItems

于 2018-09-25T11:56:01.357 回答
0

首先尝试运行此代码并检查如果我们坚持使用Structures 是否可以解决问题。然后我将尝试解释为什么这会有所帮助:

struct Car {
    var id = 0
    var start = false
    var modelNo: String

    init(start: Bool, id: Int, model: String) {
        self.start = start
        self.id = id
        self.modelNo = model
    }

    mutating func startCar(status: Bool) {
        start = status
    }
}

var arrCars: Array<Car> = [Car]()

for i in 1...10 {
    let md = Car(start: false, id: i <= 5 ? 0 : 1, model: "Model\(i)")
    arrCars.append(md)
}

private func filtered() {
    for item in arrCars {
        let filteredItems = arrCars.filter { $0.id == item.id }
        if filteredItems.count > 0 {
            // solves the problem
            arrCars[filteredItems.count-1].startCar(status: true)
            print("Will start \(arrCars[filteredItems.count-1].modelNo)")
        }
    }

    let cars = arrCars.filter { (car) -> Bool in
        car.start == true
    }

    print(cars.count)
}

filtered()
于 2018-09-25T11:46:55.593 回答