Ответ
Ключевое слово mutating используется для обозначения методов структур (struct) и перечислений (enum), которые изменяют значения их свойств (self) или self целиком.
Зачем это нужно? По умолчанию методы value-типов (структур и перечислений) не могут изменять свои свойства, потому что внутри метода self является неизменяемым (let). Модификатор mutating явно дает на это разрешение.
Пример:
struct Point {
var x = 0.0, y = 0.0
// Этот метод изменяет свойства структуры
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
// Эквивалентно: self = Point(x: self.x + deltaX, y: self.y + deltaY)
}
}
var myPoint = Point(x: 1.0, y: 1.0)
myPoint.moveBy(x: 2.0, y: 3.0) // Работает, так как myPoint объявлен через 'var'
print(myPoint) // Point(x: 3.0, y: 4.0)
let constantPoint = Point(x: 1.0, y: 1.0)
// constantPoint.moveBy(x: 2.0, y: 3.0) // Ошибка компиляции: нельзя вызвать mutating метод для константы
Важные детали:
mutatingне используется с классами (class), так как они являются reference-типами и их методы могут изменять свойства по умолчанию.- Вызов
mutatingметода для экземпляра, объявленного как константа (let), вызовет ошибку компиляции. - Внутри
mutatingметода вы можете присвоить полностью новый экземпляр свойствуself.
Ответ 18+ 🔞
Слушай, давай разберём эту штуку с mutating, а то народ иногда путается, как будто это какая-то магия, блядь.
Вот представь себе: структура (struct) или перечисление (enum) — это как бы твоя личная ксерокопия документа. По умолчанию, когда ты её кому-то передаёшь в метод, ты говоришь: «На, посмотри, но не рисуй на ней, сука, ручкой!» Это для безопасности, чтобы никто твои исходные данные не испоганил случайно.
А mutating — это когда ты такой: «Знаешь что? Вот тебе ручка, можешь прямо тут исправить опечатку, я разрешаю». То есть ты явно даёшь добро на изменение свойств самой этой структуры изнутри её же метода.
Зачем это, спрашивается, нужно? Да затем, что внутри обычного метода self — это константа (let). Попробуй её изменить — компилятор тебе мозги выест: «Ты чё, охренел? Я тебе let дал, а ты в него пишешь!». А mutating как раз и говорит компилятору: «Расслабься, братан, я тут сам всё контролирую, дай мне изменяемый доступ».
Смотри, как это выглядит в деле:
struct Координата {
var x = 0.0, y = 0.0
// Без mutating тут была бы ошибка! А так — всё легально.
mutating func подвиньНа(x deltaX: Double, y deltaY: Double) {
x += deltaX // Меняем своё же свойство
y += deltaY
// Вообще внутри можно и self целиком переписать, если захочется!
// self = Координата(x: 5, y: 5)
}
}
var мояТочка = Координата(x: 1.0, y: 1.0)
мояТочка.подвиньНа(x: 2.0, y: 3.0) // Всё работает, потому что мояТочка — `var`
print(мояТочка) // Координата(x: 3.0, y: 4.0)
let замороженнаяТочка = Координата(x: 1.0, y: 1.0)
// замороженнаяТочка.подвиньНа(x: 2.0, y: 3.0) // А вот тут, блядь, будет пиздец и ошибка компиляции! Ты её объявил как константу (`let`), а лезешь с mutating-методом. Нельзя так.
Важные нюансы, чтобы не облажаться:
- Для классов (
class) это говно не нужно. Классы — reference-типы, они всегда передаются по ссылке. Там внутри методов и так можно всё менять без всякихmutating. Другое дело, ёпта. mutatingиlet— враги на хуй. Вызвать изменяющий метод у константной структуры — всё равно что попытаться изменить надпись на застывшем бетоне. Не выйдет, только компилятор обругает.- Внутри
mutatingметода можно вообще подменить себя полностью, присвоив новый экземпляр вself. Это как сказать: «Всё, старая версия себя меня не устраивает, вот теперь я вот этот новый, красивый объект». Мощная штука, кстати.
Короче, mutating — это твой пропуск в святая святых value-типа, разрешение на внутреннюю редактуру. Используй с умом, и не пытайся вызвать его на константе, а то будет тебе ебаный стыд перед компилятором.