L'attribut de mutabilité est marqué sur un stockage (constante ou variable), pas sur un type. Vous pouvez penser que struct a deux modes: mutable et immuable . Si vous affectez une valeur struct à un stockage immuable (nous l'appelons let
ou constante dans Swift), la valeur devient le mode immuable et vous ne pouvez modifier aucun état de la valeur. (y compris l'appel de toute méthode de mutation)
Si la valeur est affectée à un stockage mutable (nous l'appelons var
ou variable dans Swift), vous êtes libre de modifier leur état et l'appel de la méthode de mutation est autorisé.
De plus, les classes n'ont pas ce mode immuable / mutable. OMI, c'est parce que les classes sont généralement utilisées pour représenter une entité référençable . Et l'entité référençable est généralement modifiable car il est très difficile de créer et de gérer des graphiques de référence d'entités de manière immuable avec des performances appropriées. Ils peuvent ajouter cette fonctionnalité plus tard, mais pas maintenant du moins.
Pour les programmeurs Objective-C, les concepts mutables / immuables sont très familiers. En Objective-C, nous avions deux classes séparées pour chaque concept, mais dans Swift, vous pouvez le faire avec une structure. La moitié du travail.
Pour les programmeurs C / C ++, c'est également un concept très familier. C'est exactement ce que const
font les mots clés en C / C ++.
En outre, la valeur immuable peut être très bien optimisée. En théorie, le compilateur Swift (ou LLVM) peut effectuer une élision de copie sur les valeurs passées parlet
, tout comme en C ++. Si vous utilisez judicieusement la structure immuable, elle surclassera les classes refcountées.
Mettre à jour
Comme @Joseph l'a affirmé, cela ne explique pas pourquoi , un peu plus.
Les structures ont deux types de méthodes. méthodes simples et mutantes . La méthode simple implique immuable (ou non mutante) . Cette séparation n'existe que pour soutenir immuable sémantique . Un objet en mode immuable ne doit pas du tout changer d'état.
Ensuite, les méthodes immuables doivent garantir cette immuabilité sémantique . Ce qui signifie qu'il ne devrait changer aucune valeur interne. Ainsi, le compilateur interdit tout changement d'état de lui-même dans une méthode immuable. En revanche, les méthodes mutantes sont libres de modifier les états.
Et puis, vous pouvez vous demander pourquoi immuable est la valeur par défaut? C'est parce qu'il est très difficile de prédire l'état futur des valeurs en mutation, et cela devient généralement la principale source de maux de tête et de bugs. Beaucoup de gens ont convenu que la solution évite les trucs mutables, puis immuable par défaut a été en tête de liste de souhaits pendant des décennies dans les langages de la famille C / C ++ et ses dérivés.
Voir le style purement fonctionnel pour plus de détails. Quoi qu'il en soit, nous avons toujours besoin de trucs mutables parce que les trucs immuables ont quelques faiblesses, et en discuter semble être hors de propos.
J'espère que ça aide.
const
à la méthode si vous voulez qu'elle ait un 'const this' et soit autorisée sur les instances constantes (les méthodes normales ne peuvent pas être utilisées si l'instance est const). Swift fait de même avec la valeur par défaut opposée: une méthode a un 'const this' par défaut et vous la marquez autrement si elle doit être interdite pour les instances constantes.Une structure est une agrégation de champs; si une instance de structure particulière est mutable, ses champs seront mutables; si une instance est immuable, ses champs seront immuables. Un type de structure doit donc être préparé pour la possibilité que les champs d'une instance particulière puissent être mutables ou immuables.
Pour qu'une méthode de structure mute les champs de la structure sous-jacente, ces champs doivent être mutables. Si une méthode qui mute les champs de la structure sous-jacente est appelée sur une structure immuable, elle essaiera de muter les champs immuables. Puisque rien de bon ne peut en résulter, une telle invocation doit être interdite.
Pour y parvenir, Swift divise les méthodes de structure en deux catégories: celles qui modifient la structure sous-jacente, et ne peuvent donc être appelées que sur des instances de structure mutable, et celles qui ne modifient pas la structure sous-jacente et devraient donc être invocables sur les instances mutables et immuables. . Cette dernière utilisation est probablement la plus fréquente et est donc la valeur par défaut.
Par comparaison, .NET n'offre actuellement (encore!) Aucun moyen de distinguer les méthodes de structure qui modifient la structure de celles qui ne le font pas. Au lieu de cela, invoquer une méthode de structure sur une instance de structure immuable obligera le compilateur à faire une copie modifiable de l'instance de structure, laissera la méthode faire ce qu'elle veut avec elle et rejettera la copie une fois la méthode terminée. Cela a pour effet de forcer le compilateur à perdre du temps à copier la structure, que la méthode la modifie ou non, même si l'ajout de l'opération de copie ne transformera presque jamais ce qui serait un code sémantiquement incorrect en code sémantiquement correct; cela fera simplement en sorte que le code qui est sémantiquement erroné dans un sens (en modifiant une valeur «immuable») soit erroné d'une manière différente (permettant au code de penser qu'il modifie une structure, mais rejetant les modifications tentées). Permettre aux méthodes struct d'indiquer si elles modifieront la structure sous-jacente peut éliminer le besoin d'une opération de copie inutile, et garantit également que les tentatives d'utilisation erronées seront signalées.
la source
Attention: les termes du profane à venir.
Cette explication n'est pas rigoureusement correcte au niveau du code le plus précis. Cependant, il a été revu par un gars qui travaille réellement sur Swift et il a dit que c'était assez bon comme explication de base.
Je veux donc essayer de répondre simplement et directement à la question du «pourquoi».
Pour être précis: pourquoi devons-nous marquer les fonctions de structure comme
mutating
lorsque nous pouvons changer les paramètres de structure sans modifier les mots-clés?Donc, dans son ensemble, cela a beaucoup à voir avec la philosophie qui maintient Swift rapide.
Vous pourriez en quelque sorte penser au problème de la gestion des adresses physiques réelles. Lorsque vous changez d'adresse, s'il y a beaucoup de personnes qui ont votre adresse actuelle, vous devez les informer toutes que vous avez déménagé. Mais si personne n'a votre adresse actuelle, vous pouvez simplement vous déplacer où vous voulez, et personne n'a besoin de savoir.
Dans cette situation, Swift est un peu comme le bureau de poste. Si beaucoup de personnes avec beaucoup de contacts se déplacent beaucoup, cela a des frais généraux très élevés. Il doit payer un grand nombre de personnes pour gérer toutes ces notifications, et le processus prend beaucoup de temps et d'efforts. C'est pourquoi l'état idéal de Swift est que chacun dans sa ville ait le moins de contacts possible. Ensuite, il n'a pas besoin d'un gros personnel pour gérer les changements d'adresse, et il peut faire tout le reste plus rapidement et mieux.
C'est aussi pourquoi les gens de Swift raffolent tous des types de valeur par rapport aux types de référence. Par nature, les types de référence accumulent des "contacts" partout, et les types de valeur n'ont généralement pas besoin de plus d'un couple. Les types de valeur sont "Swift" -er.
Revenons donc à la petite image:
structs
. Les structures sont un gros problème dans Swift car elles peuvent faire la plupart des choses que les objets peuvent faire, mais ce sont des types de valeur.Continuons l'analogie de l'adresse physique en imaginant une
misterStruct
qui habitesomeObjectVille
. L'analogie est un peu déconcertée ici, mais je pense qu'elle est toujours utile.Donc, pour modéliser la modification d'une variable sur un
struct
, disonsmisterStruct
a les cheveux verts, et obtient un ordre de passer aux cheveux bleus. L'analogie est déconcertée, comme je l'ai dit, mais ce qui se passe en quelque sorte, c'est qu'au lieu de changermisterStruct
de cheveux, la personne âgée déménage et une nouvelle personne aux cheveux bleus entre, et cette nouvelle personne commence à s'appelermisterStruct
. Personne n'a besoin de recevoir une notification de changement d'adresse, mais si quelqu'un regarde cette adresse, il verra un gars aux cheveux bleus.Modélisons maintenant ce qui se passe lorsque vous appelez une fonction sur un fichier
struct
. Dans ce cas, c'est commemisterStruct
obtenir une commande telle quechangeYourHairBlue()
. Alors le bureau de poste donne l'instructionmisterStruct
"d'aller changer vos cheveux en bleu et me dire quand vous avez terminé."S'il suit la même routine qu'avant, s'il fait ce qu'il a fait lorsque la variable a été modifiée directement, ce qu'il
misterStruct
va faire est de quitter sa propre maison et d'appeler une nouvelle personne aux cheveux bleus. Mais c'est ça le problème.L'ordre était "allez changer vos cheveux en bleu et dites-moi quand vous avez terminé", mais c'est le gars vert qui a reçu cet ordre. Une fois que le gars bleu a emménagé, une notification "travail terminé" doit encore être renvoyée. Mais le gars bleu n'en sait rien.
[Pour vraiment contrarier cette analogie, quelque chose d'horrible, ce qui est techniquement arrivé à un gars aux cheveux verts, c'est qu'après son déménagement, il s'est immédiatement suicidé. Donc , il ne peut en aviser quiconque que la tâche est terminée , soit! ]
Pour éviter ce problème, dans des cas comme celui-ci uniquement , Swift doit se rendre directement à la maison à cette adresse et changer les cheveux de l'habitant actuel . C'est un processus complètement différent de celui d'envoyer simplement un nouveau gars.
Et c'est pourquoi Swift veut que nous utilisions le
mutating
mot - clé!Le résultat final ressemble à tout ce qui doit faire référence à la structure: l'habitant de la maison a maintenant les cheveux bleus. Mais les processus pour y parvenir sont en fait complètement différents. On dirait que ça fait la même chose, mais ça fait une chose très différente. Cela fait quelque chose que les structures Swift en général ne font jamais.
Donc, pour donner un peu d'aide au pauvre compilateur, et ne pas l'obliger à déterminer si une fonction mute
struct
ou non, seule, pour chaque fonction struct, on nous demande d'avoir pitié et d'utiliser lemutating
mot - clé.En substance, pour aider Swift à rester rapide, nous devons tous faire notre part. :)
ÉDITER:
Hey mec / dudette qui m'a refusé, je viens de réécrire complètement ma réponse. Si cela vous convient mieux, supprimerez-vous le vote défavorable?
la source
Les structures Swift peuvent être instanciées sous forme de constantes (via
let
) ou de variables (viavar
)Considérez la
Array
structure de Swift (oui, c'est une structure).Pourquoi l'ajout n'a-t-il pas fonctionné avec les noms de planètes? Parce que append est marqué avec le
mutating
mot - clé. Et depuis qu'il aplanetNames
été déclaré en utilisantlet
, toutes les méthodes ainsi marquées sont interdites.Dans votre exemple, le compilateur peut indiquer que vous modifiez la structure en affectant une ou plusieurs de ses propriétés en dehors d'un fichier
init
. Si vous modifiez votre code un peu , vous verrez quex
ety
ne sont pas toujours accessibles en dehors de la struct. Remarquez lelet
sur la première ligne.la source
Prenons une analogie avec C ++. Une méthode struct en Swift étant
mutating
/ non-mutating
est analogue à une méthode en C ++ étant non-const
/const
. De même, une méthode marquéeconst
en C ++ ne peut pas muter la structure.En C ++, vous pouvez également "modifier une variable depuis l'extérieur de la structure" - mais uniquement si vous avez une
const
variable non struct. Si vous avez uneconst
variable struct, vous ne pouvez pas l'assigner à un var, et vous ne pouvez pas non plus appeler une non-const
méthode. De même, dans Swift, vous ne pouvez modifier une propriété d'un struct que si la variable struct n'est pas une constante. Si vous avez une constante struct, vous ne pouvez pas affecter à une propriété et vous ne pouvez pas non plus appeler unemutating
méthode.la source
Je me suis demandé la même chose lorsque j'ai commencé à apprendre Swift, et chacune de ces réponses, tout en ajoutant peut-être quelques idées, est un peu verbeuse et déroutante en soi. Je pense que la réponse à votre question est en fait assez simple…
La méthode de mutation définie dans votre structure veut la permission de modifier chaque instance d'elle-même qui sera jamais créée à l'avenir. Que faire si l'une de ces instances est affectée à une constante immuable avec
let
? Oh oh. Pour vous protéger de vous-même (et pour permettre à l'éditeur et au compilateur de savoir ce que vous essayez de faire), vous êtes obligé d'être explicite lorsque vous voulez donner à une méthode d'instance ce type de pouvoir.En revanche, la définition d'une propriété depuis l' extérieur de votre structure fonctionne sur une instance connue de cette structure. S'il est attribué à une constante, Xcode vous en informera au moment où vous avez tapé l'appel de méthode.
C'est l'une des choses que j'aime chez Swift au fur et à mesure que je commence à l'utiliser: être alerté des erreurs lorsque je les saisis. Bien sûr, bat le diable du dépannage de bogues JavaScript obscurs!
la source
SWIFT: utilisation de la fonction de mutation dans Structs
Les programmeurs Swift ont développé Structs de telle sorte que ses propriétés ne puissent pas être modifiées dans les méthodes Struct. Par exemple, vérifiez le code ci-dessous
Lors de l'exécution du code ci-dessus, nous obtenons une erreur car nous essayons d'attribuer une nouvelle valeur à la population de propriétés de Struct City. Par défaut, les propriétés Structs ne peuvent pas être mutées dans ses propres méthodes. C'est ainsi que les développeurs Apple l'ont construit, de sorte que les Structs aient un caractère statique par défaut.
Comment pouvons-nous le résoudre? Quelle est l'alternative?
Mot-clé mutant:
Déclarer une fonction comme mutante à l'intérieur de Struct nous permet de modifier les propriétés dans Structs. Ligne n °: 5, du code ci-dessus change comme ceci,
Nous pouvons maintenant attribuer la valeur de la nouvelle population à la population de propriétés dans le cadre de la méthode.
Remarque :
Si nous utilisons let au lieu de var pour les objets Struct, alors nous ne pouvons muter la valeur d'aucune propriété.C'est également la raison pour laquelle nous obtenons une erreur lorsque nous essayons d'appeler une fonction de mutation en utilisant l'instance de let. Il est donc préférable d'utiliser var chaque fois que vous modifiez la valeur d'une propriété.
J'adorerais entendre vos commentaires et vos pensées… ..
la source