Swift结构突变变量不起作用?

时间:2018-09-25 11:22:07

标签: ios swift struct swift4 mutating-function

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

因此,基本上,我以一种非常简单的方式解决了问题,我有一个类Car,该类具有3个变量idstartmodelNo

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

有一张检查,前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()

任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:3)

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

您说:

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

因此,lastItem包含您要启动的汽车的实例。在幕后,这是filteredItems中的汽车实例,而arrCars中的汽车实例也是如此。但是,一旦您对Car中的lastItem进行了突变,便会创建一个副本,因此lastItem 不再具有与arrCars中的实例相同的实例< / em>。 filteredItemsarrCars仍包含原始的未更改的Car实例。

您可以将Car更改为class而不是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)
}

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

答案 1 :(得分:2)

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

if var lastItem = filteredItems.last

这将产生一个lastItem的汽车。但这与filteredItems中的 车不同。

这是因为结构是值类。分配复制结构。因此,对lastItem所做的操作不会影响filteredItems内部的内容。

因此, 没有任何麻烦。您正在变异lastItem就好了!问题是lastItem汽车与filteredItems内的任何汽车都不是同一物体。

答案 2 :(得分:0)

如果我们坚持使用Structure,请首先尝试运行此代码并检查它是否解决了问题。然后,我将尝试解释为什么有帮助:

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()