Почему Swift выдает «Невозможно использовать мутирующий член для неизменяемого значения» в некоторых вызовах цепочки, но не в других?

В Swift у меня есть собственная структура Deque с различными методами изменения для добавления и удаления элементов. Когда я связываю вызовы методов, например Deque.pushBack(contentsOf: ...), я сталкиваюсь с ошибкой «Невозможно использовать мутирующий элемент для неизменяемого значения: вызов функции возвращает неизменяемое значение». Однако когда я использую тот же шаблон цепочки для такой переменной, как b, он работает нормально. Может кто-нибудь объяснить, почему это происходит? Связано ли это с тем, что функция сопоставления является глобальной функцией? Как я могу решить эту проблему?

 struct Deque {
     private var arrayDeque: [Int] = []
     
     mutating func pushFront(_ element: Int) {
         arrayDeque.insert(element, at: 0)
     }
     
     @discardableResult
     mutating func pushFront(contentsOf elements: Int...) -> Deque {
         for element in elements.reversed() {
             pushFront(element)
         }
         return self
     }
     
     mutating func pushBack(_ element: Int) {
         arrayDeque.append(element)
     }
     
     @discardableResult
     mutating func pushBack(contentsOf elements: Int...) -> Deque {
         for element in elements {
             pushBack(element)
         }
         return self
     }
     
     @discardableResult
     mutating func popFront() -> Deque? {
         guard !isEmpty else { return nil }
         var copy = self
         copy.arrayDeque.removeFirst()
         return copy
     }
     
     @discardableResult
     mutating func popBack() -> Deque? {
         guard !isEmpty else { return nil }
         var copy = self
         copy.arrayDeque.removeLast()
         return copy
     }
     
     var isEmpty: Bool {
         return arrayDeque.isEmpty
     }
     
     var count: Int {
         return arrayDeque.count
     }
     
     func peekFront() -> Int? {
         return arrayDeque.first
     }
     
     func peekBack() -> Int? {
         return arrayDeque.last
     }
 }

 func match(_ xs: Deque) -> Bool { ... }

 // gives me error
 let a = match(Deque().pushBack(contentsOf: 1, 2, 1, 2, 1))

 // works fine
 var b = Deque()
 let b2 = b.pushBack(contentsOf: 1, 2, 1, 2, 1)
 let b3 = match(b2)

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

Я пытаюсь понять, почему Swift ведет себя по-разному в этих сценариях и как я могу обеспечить согласованное поведение при объединении вызовов методов в пользовательские структуры данных. Будем очень признательны за любые идеи или объяснения! (Я новичок в этом, если вы сможете объяснить в общих чертах, было бы здорово, спасибо)

Также объяснение в

См. stackoverflow.com/a/48287958/1187415

Martin R 23.04.2024 21:00
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
1
1
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Технической причины, по которой вам не разрешают это сделать, нет, но в большинстве случаев. вызов изменяющей функции по возвращаемому значению, скорее всего, является ошибкой. (См. также) Рассмотрим довольно надуманный пример:

var deque = Deque()
func returnADeque() -> Deque { return deque }

// suppose this is allowed
returnADeque().pushBack(1)

На самом деле это не изменит глобальную переменную deque. Deque — это структура (тип значения), поэтому returnADeque возвращает ее копию.

То же самое относится и к инициализаторам. С точки зрения вызывающей стороны, инициализатор — это просто функция, которая возвращает экземпляр любого типа, который она инициализирует. Предположим, pushBack не return self, тогда Deque().pushBack(contentsOf: 1, 2, 1, 2, 1) не будет выполнять никакой полезной работы. Вы создаете Deque, затем помещаете в него несколько чисел, а затем отбрасываете его, не используя ничего из того, что вы вставили.

Чтобы выполнить такую ​​цепочку, вы можете изменить Deque на класс (ссылочный тип), который имеет другую семантику. Вы также можете создать две версии каждой функции: одну, которая не является mutating и возвращает self для цепочки, и другую, которая есть mutating и не возвращает self.

 mutating func pushBack(contentsOf elements: Int...) {
     for element in elements {
         pushBack(element)
     }
 }

func pushedBack(contentsOf elements: Int...) -> Deque {
    var copy = self
    // normally you can reuse the mutating function here, but because pushBack
    // takes a variadic Int..., it is not possible in this case
    for element in elements {
        copy.pushBack(element)
    }
    return copy
}

Метод, позволяющий создавать цепочки, должен использовать частицу прошедшего времени глагола, чтобы следовать соглашениям об именах, используемым в стандартной библиотеке. shuffle() против shuffled(), reverse() против reversed() и т. д.

крутое объяснение. То есть то же правило применяется, даже если я использую инфиксный оператор?

Adrian 24.04.2024 13:20

@Adrian Предполагая, что вы имеете в виду инфиксный оператор, такой как func +(inout deque: Deque, item: Int), да, вы не сможете вызвать его с возвращаемым значением функции в качестве LHS. Если вы не можете вызвать мутирующий метод для чего-либо, эту вещь также нельзя передать в качестве параметра inout.

Sweeper 24.04.2024 13:25

func !><T, U>(_ f: ATescaping (T) -> U, _ g: ATescaping (U) -> Bool) -> (T) -> Bool Я использовал это, и да, он выдаст то же самое ошибка.

Adrian 24.04.2024 13:28

Другие вопросы по теме