Атрибут изменчивости отмечен для хранилища (константы или переменной), а не для типа. Вы можете думать, что у struct есть два режима: изменяемый и неизменный . Если присвоить значение структуры для неизменного хранения (мы называем его let
или константу в Swift) значение становится неизменяемым режимом, и вы не можете изменить любое состояние в стоимости. (включая вызов любого метода изменения)
Если значение присваивается изменяемому хранилищу (мы называем его var
или переменной в Swift), вы можете изменять их состояние, и разрешается вызов метода изменения.
Кроме того, у классов нет этого неизменяемого / изменяемого режима. ИМО, это потому, что классы обычно используются для представления ссылочной сущности. А ссылочная сущность обычно является изменяемой, потому что очень сложно создавать ссылочные графы сущностей и управлять ими неизменным образом с надлежащей производительностью. Они могут добавить эту функцию позже, но не сейчас.
Программистам на Objective-C очень знакомы концепции изменчивого / неизменяемого. В Objective-C у нас было два отдельных класса для каждой концепции, но в Swift вы можете сделать это с помощью одной структуры. Половина работы.
Для программистов на C / C ++ это тоже очень знакомая концепция. Это именно то, что const
ключевое слово делает в C / C ++.
Кроме того, неизменяемое значение можно очень хорошо оптимизировать. Теоретически компилятор Swift (или LLVM) может выполнять копирование переданных значений let
, как в C ++. Если вы разумно используете неизменяемую структуру, она превзойдет классы с пересчетом.
Обновить
Поскольку @Joseph утверждает, что это не объясняет , почему , я добавляю немного больше.
У структур есть два типа методов. простые и мутирующие методы. Обычный метод подразумевает неизменяемость (или неизменяемость) . Это разделение существует только для поддержки неизменной семантики. Объект в неизменяемом режиме вообще не должен изменять свое состояние.
Затем неизменяемые методы должны гарантировать эту семантическую неизменность . Это означает, что он не должен изменять никаких внутренних значений. Таким образом, компилятор запрещает любое изменение своего состояния в неизменяемом методе. Напротив, методы изменения могут изменять состояния.
И тогда у вас может возникнуть вопрос, почему по умолчанию используется неизменяемый? Это потому, что очень трудно предсказать будущее состояние изменяющихся значений, и это обычно становится основным источником головной боли и ошибок. Многие люди согласились с тем, что решение избегает изменяемых вещей, и тогда неизменяемость по умолчанию была на первом месте в списке желаний на протяжении десятилетий в языках семейства C / C ++ и его производных.
Подробнее см. Чисто функциональный стиль . В любом случае, нам все еще нужны изменяемые материалы, потому что у неизменяемых есть некоторые слабые места, и обсуждение их, похоже, не в теме.
Надеюсь, это поможет.
const
к методу, если вы хотите, чтобы он имел 'const this' и разрешался для константных экземпляров (обычные методы не могут использоваться, если экземпляр имеет значение const). Swift делает то же самое с противоположным значением по умолчанию: метод имеет по умолчанию const this, и вы отмечаете его иначе, если он должен быть запрещен для постоянных экземпляров.Структура - это совокупность полей; если конкретный экземпляр структуры является изменяемым, его поля будут изменяемыми; если экземпляр неизменен, его поля будут неизменными. Таким образом, тип структуры должен быть подготовлен к тому, что поля любого конкретного экземпляра могут быть изменяемыми или неизменяемыми.
Чтобы метод структуры мог изменять поля базовой структуры, эти поля должны быть изменяемыми. Если метод, изменяющий поля базовой структуры, вызывается в неизменяемой структуре, он пытается изменить неизменяемые поля. Поскольку ничего хорошего из этого не выйдет, такое обращение нужно запретить.
Для этого Swift делит методы структуры на две категории: те, которые изменяют базовую структуру и, таким образом, могут быть вызваны только для изменяемых экземпляров структуры, и те, которые не изменяют базовую структуру и, таким образом, должны вызываться как в изменяемых, так и в неизменяемых экземплярах. . Последнее использование, вероятно, более частое, и поэтому используется по умолчанию.
Для сравнения, .NET в настоящее время (все еще!) Не предлагает способов отличить методы структуры, которые изменяют структуру, от методов, которые этого не делают. Вместо этого вызов метода структуры для экземпляра неизменяемой структуры заставит компилятор сделать изменяемую копию экземпляра структуры, позволить методу делать с ней все, что он хочет, и отбросить копию, когда метод будет выполнен. Это приводит к тому, что компилятор заставляет компилятор тратить время на копирование структуры вне зависимости от того, модифицирует ее метод или нет, даже если добавление операции копирования почти никогда не превратит семантически неправильный код в семантически правильный код; это просто приведет к тому, что код, который семантически неверен в одном отношении (изменение «неизменяемого» значения), будет неправильным в другом (позволяя коду думать, что он изменяет структуру, но отбрасывая предпринятые изменения). Разрешение методов структуры указывать, будут ли они изменять базовую структуру, может устранить необходимость в бесполезной операции копирования, а также гарантирует, что попытка ошибочного использования будет отмечена.
источник
Осторожно: условия непрофессионала впереди.
Это объяснение не совсем корректно на самом мелком уровне кода. Однако он был рассмотрен парнем, который действительно работает над Swift, и сказал, что это достаточно хорошо в качестве основного объяснения.
Поэтому я хочу попытаться просто и прямо ответить на вопрос «почему».
Чтобы быть точным: почему мы должны отмечать структурные функции,
mutating
когда мы можем изменять параметры структуры без каких-либо модифицирующих ключевых слов?Итак, большая картина, это во многом связано с философией, которая поддерживает Swift Swift .
Вы могли бы думать об этом как о проблеме управления реальными физическими адресами. Когда вы меняете свой адрес, если у многих людей есть ваш текущий, вы должны уведомить их всех о том, что вы переехали. Но если ни у кого нет вашего текущего адреса, вы можете просто переехать куда хотите, и никому не нужно знать.
В этой ситуации Swift чем-то похож на почтовое отделение. Если много людей с большим количеством контактов много перемещаются, это очень дорого обходится. За обработку всех этих уведомлений приходится платить большому количеству людей, а процесс отнимает много времени и усилий. Вот почему идеальное состояние Swift - чтобы у всех в городе было как можно меньше контактов. Тогда ему не понадобится большой персонал для обработки изменений адреса, и он сможет делать все остальное быстрее и лучше.
Вот почему все Swift-люди бредят о типах значений и ссылочных типах. По своей природе ссылочные типы создают «контакты» повсюду, а типам значений обычно не требуется больше пары. Типы значений - "Swift" -er.
Итак , вернемся к маленькой картинке:
structs
. Структуры имеют большое значение в Swift, потому что они могут делать большинство вещей, которые могут делать объекты, но они являются типами значений.Давайте продолжим аналогию с физическим адресом, представив,
misterStruct
что живет вsomeObjectVille
. Аналогия здесь немного запутана, но я думаю, что она все же полезна.Итак, для модели, изменяющей переменную на a
struct
, допустим, уmisterStruct
нее зеленые волосы, и она получает команду переключиться на синие волосы. Как я уже сказал, аналогия оказывается неудачной, но происходит нечто вроде того, что вместо того, чтобы менятьmisterStruct
прическу, старый человек уезжает, а новый человек с голубыми волосами входит в комнату, и этот новый человек начинает называть себяmisterStruct
. Никому не нужно получать уведомление о смене адреса, но если кто-нибудь посмотрит на этот адрес, он увидит парня с синими волосами.Теперь давайте смоделируем, что происходит, когда вы вызываете функцию в
struct
. В данном случае это какmisterStruct
получить заказ типаchangeYourHairBlue()
. Итак, почтовое отделение доставляет инструкцию:misterStruct
«Иди смени свои волосы на синие и скажи мне, когда закончишь».Если он следует той же рутине, что и раньше, если он делает то, что делал, когда переменная была изменена напрямую, то
misterStruct
он переедет из собственного дома и вызовет нового человека с синими волосами. Но вот в чем проблема.Приказ был: «Иди, смени свои волосы на синие и скажи мне, когда закончишь», но этот приказ получил зеленый парень. После того, как синий парень въезжает, уведомление о завершении работы все равно нужно отправить обратно. Но синий парень ничего об этом не знает.
[Если по-настоящему задуматься над этой аналогией, что-то ужасное, технически с зеленоволосым парнем случилось то, что после того, как он переехал, он немедленно покончил с собой. Значит, он не может никого уведомить о том, что задача выполнена ! ]
Чтобы избежать этой проблемы, в случаях , как это только , Swift должен идти непосредственно к дому по этому адресу и фактически изменить волосы текущего обитателя . Это совершенно другой процесс, чем просто отправить нового парня.
Вот почему Swift хочет, чтобы мы использовали
mutating
ключевое слово!Конечный результат выглядит одинаково для всего, что должно относиться к структуре: теперь у обитателя дома голубые волосы. Но на самом деле процессы для его достижения совершенно разные. Похоже, он делает то же самое, но делает совсем другое. Это то, чего вообще не делают Swift-структуры.
Итак, чтобы немного помочь плохому компилятору и не заставлять его выяснять, мутирует ли функция сама по себе
struct
или нет для каждой отдельной структурной функции, нас просят сжалиться и использоватьmutating
ключевое слово.По сути, чтобы помочь Swift оставаться быстрым, мы все должны внести свой вклад. :)
РЕДАКТИРОВАТЬ:
Привет, чувак / чувак, который отверг меня, я просто полностью переписал свой ответ. Если вам так больше нравится, вы уберете отрицательный голос?
источник
Структуры Swift могут быть созданы как константы (через
let
) или как переменные (черезvar
).Рассмотрим
Array
структуру Swift (да, это структура).Почему добавление не работает с названиями планет? Потому что добавление помечено
mutating
ключевым словом. И посколькуplanetNames
было объявлено использованиеlet
, все методы, отмеченные таким образом, являются запрещенными.В вашем примере компилятор может сказать, что вы изменяете структуру, назначая одно или несколько ее свойств за пределами
init
. Если вы немного измените свой код, вы увидите это,x
иy
не всегда доступны за пределами структуры. Обратите вниманиеlet
на первую строку.источник
Рассмотрим аналогию с C ++. Метод структуры в Swift
mutating
be / not-mutating
аналогичен методу в C ++, являющемуся не-const
/const
.const
Аналогичным образом, метод, отмеченный в C ++, не может изменять структуру.В C ++ вы также можете «изменить переменную вне структуры» - но только если у вас есть
const
неструктурная переменная. Если у вас естьconst
структурная переменная, вы не можете назначить ее переменной, а также не можете вызвать не-const
метод. Точно так же в Swift вы можете изменить свойство структуры, только если переменная структуры не является константой. Если у вас есть структурная константа, вы не можете назначить ее свойству, а также не можете вызватьmutating
метод.источник
Я задавался вопросом о том же, когда начинал изучать Swift, и каждый из этих ответов, возможно, добавляющих некоторые идеи, сам по себе многословен и запутан. Я думаю, что ответ на ваш вопрос на самом деле довольно прост ...
Метод изменения, определенный внутри вашей структуры, требует разрешения на изменение каждого самого себя, который когда-либо будет создан в будущем. Что, если один из этих экземпляров будет назначен неизменной константе с помощью
let
? Ой ой. Чтобы защитить себя от самого себя (и дать возможность редактору и компилятору знать, что вы пытаетесь сделать), вы вынуждены быть явным, когда хотите предоставить методу экземпляра такую силу.Напротив, установка свойства извне вашей структуры работает с известным экземпляром этой структуры. Если он назначен константе, Xcode сообщит вам об этом в тот момент, когда вы наберете вызов метода.
Это одна из вещей, которые мне нравятся в Swift, когда я начинаю его все больше использовать - получать предупреждения об ошибках по мере их ввода. Конечно, это лучше, чем устранять неясные ошибки JavaScript!
источник
SWIFT: использование функции изменения в структурах
Программисты Swift разработали Structs таким образом, что его свойства нельзя изменить в методах Struct. Например, проверьте код, приведенный ниже
При выполнении вышеуказанного кода мы получаем ошибку, потому что мы пытаемся присвоить новое значение совокупности свойств Struct City. По умолчанию свойства Structs нельзя изменять внутри его собственных методов. Так разработчики Apple построили его, поэтому структуры по умолчанию будут иметь статический характер.
Как решить эту проблему? Какая альтернатива?
Мутирующее ключевое слово:
Объявление функции как изменяющейся внутри Struct позволяет нам изменять свойства в Structs. Строка № 5 приведенного выше кода меняется на это:
Теперь мы можем присвоить значение newpopulation имущества населения в рамках метода.
Примечание :
Если мы используем let вместо var для объектов Struct, тогда мы не сможем изменить значение каких-либо свойств. Также по этой причине мы получаем ошибку, когда пытаемся вызвать функцию изменения с помощью экземпляра let. Поэтому лучше использовать var всякий раз, когда вы меняете значение свойства.
Хотелось бы услышать ваши комментарии и мысли… ..
источник