web-dev-qa-db-fra.com

F #: laissez mutable vs ref

Premièrement, je reconnais la possibilité que cette question puisse être un double; faites le moi savoir.

Je suis curieux de savoir quelle est la "meilleure pratique" générale pour les situations où la mutabilité est souhaitée. F # semble offrir deux fonctionnalités pour cela: le let mutable la liaison, qui semble fonctionner comme des variables dans "la plupart" des langues, et la cellule de référence (créée avec la fonction ref) qui nécessite un déréférencement explicite à utiliser.

Il y a quelques cas où l'un est "forcé" dans l'un ou l'autre: l'interopérabilité .NET a tendance à utiliser mutable avec <-, et dans les calculs de workflow, il faut utiliser ref avec :=. Ces cas sont donc assez clairs, mais je suis curieux de savoir quoi faire lorsque je crée mes propres variables mutables en dehors de ces scénarios. Quel avantage un style a-t-il sur l'autre? (Il serait peut-être utile de mieux comprendre la mise en œuvre.)

Merci!

79
J Cooper

Je ne peux supporter que ce que gradbot a dit - quand j'ai besoin d'une mutation, je préfère let mutable.

Concernant l'implémentation et les différences entre les deux - ref cellules sont essentiellement implémentées par un enregistrement très simple qui contient un champ d'enregistrement mutable. Vous pouvez les écrire facilement vous-même:

type ref<'T> =  // '
  { mutable value : 'T } // '

// the ref function, ! and := operators look like this:
let (!) (a:ref<_>) = a.value
let (:=) (a:ref<_>) v = a.value <- v
let ref v = { value = v }

Une différence notable entre les deux approches est que let mutable stocke la valeur mutable sur la pile (en tant que variable mutable en C #) tandis que ref stocke la valeur mutable dans un champ d'un enregistrement alloué par segment de mémoire. Cela peut avoir un impact sur les performances, mais je n'ai pas de chiffres ...

Grâce à cela, les valeurs mutables qui utilisent ref peuvent être aliasées - ce qui signifie que vous pouvez créer deux valeurs qui font référence à la même valeur mutable:

let a = ref 5  // allocates a new record on the heap
let b = a      // b references the same record
b := 10        // modifies the value of 'a' as well!

let mutable a = 5 // mutable value on the stack
let mutable b = a // new mutable value initialized to current value of 'a'
b <- 10           // modifies the value of 'b' only!
128
Tomas Petricek

Question connexe: "Vous avez mentionné que les valeurs mutables locales ne peuvent pas être capturées par une fermeture, vous devez donc utiliser ref à la place. La raison en est que mutable les valeurs capturées dans la fermeture doivent être allouées sur le tas (car la fermeture est allouée sur le tas). " de F # ref-mutable vars vs champs d'objet

Je pense let mutable est préféré aux cellules de référence. Personnellement, je n'utilise des cellules de référence que lorsqu'elles sont nécessaires.

La plupart du code que j'écris n'utilise pas de variables mutables grâce aux appels de récursivité et de queue. Si j'ai un groupe de données mutables, j'utilise un enregistrement. Pour les objets que j'utilise let mutable pour créer des variables mutables privées. Je n'utilise vraiment les cellules de référence que pour les fermetures, généralement les événements.

18
gradbot

Comme décrit dans cet article du blog MSDN dans la section Utilisation simplifiée des valeurs mutables , vous n'avez plus besoin de cellules ref pour les lambdas. Donc, en général, vous n'en avez plus besoin du tout.

7
Andrii

Cet article par Brian pourrait fournir une réponse.

Les mutables sont faciles à utiliser et efficaces (sans emballage), mais ne peuvent pas être capturés dans des lambdas. Les cellules de référence peuvent être capturées, mais sont verbeuses et moins efficaces (? - pas sûr de cela).

4
Mau

Vous voudrez peut-être jeter un œil à la section Mutable Data dans le wikibook.

Pour plus de commodité, voici quelques citations pertinentes:

Le mot clé mutable est fréquemment utilisé avec les types d'enregistrement pour créer des enregistrements mutables

Les variables mutables sont quelque peu limitées: les mutables sont inaccessibles en dehors de la portée de la fonction où elles sont définies. Plus précisément, cela signifie qu'il n'est pas possible de référencer un mutable dans une sous-fonction d'une autre fonction.

Les cellules de référence contournent certaines des limites des mutables. En fait, les cellules ref sont de type de données très simples qui enveloppent un champ mutable dans un type d'enregistrement.

Étant donné que les cellules ref sont allouées sur le tas, elles peuvent être partagées entre plusieurs fonctions

3
danlei