Частичное применение метода "mutating" не допускается

struct MyStruct {
    var count = 0

    mutating func add(amount: Int) {
        count += amount
    }
}

var myStruct = MyStruct()

[1, 2, 3, 4].forEach(myStruct.add)
// Partial application of 'mutating' method is not allowed

Почему не используется forEach, как это допустимо для методов мутирования? Я знаю, что я мог бы сделать

for number in [1, 2, 3, 4] {
    myStruct.add(number)
}

или

[1, 2, 3, 4].forEach { myStruct.add($0) }

но не так чисты, как

[1, 2, 3, 4].forEach(myStruct.add)

Ответ 1

Ключ к типу значения заключается в том, что присваивание создает копию. Этот контракт также влияет на то, как люди могут рассуждать о своем коде. Например, если вы передали метод Int в метод, вы можете быть уверены, что это значение не изменится из-под вас, даже если исходный int прошел в направлении отправки в другой поток и имеет расчеты, выполненные в другом месте.

То же самое верно для structs. Вот почему в быстром определении методов, которые могут изменить "я", если это тип значения, вы должны определить его как "мутирующий". Это говорит о том, что он одновременно переназначает вашу переменную с новым значением. Например, когда вы вызываете свой метод добавления с помощью "3", вы можете думать о том, что он выполняет что-то похожее на:

var myStruct = MyStruct()
var tmp = myStruct
tmp.count = tmp.count + 3
myStruct = tmp

Теперь причина, по которой вы попадаете в ошибку, состоит в том, что частично применение мутирующей функции нарушит этот контракт. Если вы можете сохранить закрытие как let myStructAdd = myStruct.add, то в какой-то более поздний момент вы можете вызвать myStructAdd(3), и он попытается изменить myStruct. Это даст ссылочную семантику для типа значения, так как теперь у вас есть возможность изменить myStruct в более поздней точке, даже с помощью другого метода.

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