Swift struct, изменяющая переменную, не работает?

Я не могу изменить свою переменную класса модели, даже используя mutating func ключевое слово в методе?

В общем, я очень легко обернул свою проблему, у меня есть класс Car который имеет 3 переменных id, start, а также modelNo

После этого инициализируйте пустой массив моделей автомобилей, а затем я хочу показать 10 автомобилей, создав диапазон для цикла, который повторяется 1...10, инициализируя класс модели Car и добавляя его в массив оригинальных автомобилей.

Идет проверка первых 5 автомобилей с идентификатором 0 и последними 5 автомобилями с идентификатором 1

Мне нужен фильтр, в котором будет запускаться последняя машина этого же идентификатора, поэтому я создал метод, отфильтрованный и модифицирующий переменную запуска, но не в состоянии изменить его. Можете ли вы помочь мне, что я делаю не так?

Пожалуйста, посмотрите мой полный код и скопируйте его на игровую площадку.

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 ответа

Решение

Создание mutating Функция на структуре не меняет семантику значений структур. Как только экземпляр структуры мутирует, создается копия.

Ты говоришь:

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

Так, lastItem содержит экземпляр автомобиля, который вы собираетесь запустить. Под крышками это тот же экземпляр автомобиля, который находится в filteredItems, который является тем же экземпляром, который находится в arrCars, Но, как только вы мутируете Car в lastItemкопия сделана, так lastItem больше не имеет тот же экземпляр, что и вarrCars, filteredItems а также arrCars до сих пор содержат оригинал, без изменений 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)
}

Однако, когда объект модели требует изменчивости или состояния, структура, вероятно, не подходит.

Ответы, которые вы получили до сих пор, не являются неправильными, но они кажутся немного запутанными. Давайте посмотрим на это немного проще. Проблема в этой строке:

if var lastItem = filteredItems.last

Это дает автомобиль как lastItem, Но это не та же машина, что и та, что в filteredItems,

Это потому, что структура является классом значений. Назначение копирует структуру. Таким образом, что вы делаете для lastItem не влияет на то, что сидит внутри filteredItems,

Таким образом, у вас нет проблем с изменением структуры. Вы мутируете lastItem просто хорошо! Проблема в том, что lastItem Автомобиль не тот же объект, что и любой автомобиль внутри filteredItems,

Во-первых, попробуйте запустить этот код и проверить, если он решает проблему, если мы придерживаемся 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()
Другие вопросы по тегам