Quelle est la différence entre
- un paramètre passé par référence
- un paramètre passé par valeur?
Pourriez-vous me donner quelques exemples, s'il vous plaît?
Quelle est la différence entre
Pourriez-vous me donner quelques exemples, s'il vous plaît?
Réponses:
D'abord et avant tout, la distinction «passe par valeur vs passe par référence» telle que définie dans la théorie CS est maintenant obsolète parce que la technique définie à l'origine comme «passe par référence» est depuis tombée en disgrâce et est rarement utilisée maintenant. 1
Les langues plus récentes 2 ont tendance à utiliser une paire de techniques différentes (mais similaires) pour obtenir les mêmes effets (voir ci-dessous), qui est la principale source de confusion.
Une source secondaire de confusion est le fait que dans "passer par référence", "référence" a un sens plus étroit que le terme général "référence" (parce que la phrase la précède).
Maintenant, la définition authentique est:
Lorsqu'un paramètre est transmis par référence , l'appelant et l'appelé utilisent la même variable pour le paramètre. Si l'appelé modifie la variable de paramètre, l'effet est visible pour la variable de l'appelant.
Lorsqu'un paramètre est transmis par valeur , l'appelant et l'appelé ont deux variables indépendantes avec la même valeur. Si l'appelé modifie la variable de paramètre, l'effet n'est pas visible pour l'appelant.
Les points à noter dans cette définition sont:
"Variable" signifie ici la variable de l'appelant (locale ou globale) elle - même - c'est -à -dire que si je passe une variable locale par référence et que je l'affecte, je changerai la variable de l'appelant elle-même, pas par exemple ce qu'elle pointe si c'est un pointeur .
La signification de "référence" dans "passer par référence" . La différence avec le terme général de "référence" est que cette "référence" est temporaire et implicite. Ce que l'appelé obtient essentiellement est une "variable" qui est en quelque sorte "la même" que l'original. La manière dont cet effet est atteint est sans importance (par exemple, le langage peut également exposer certains détails de mise en œuvre - adresses, pointeurs, déréférencement - tout cela n'est pas pertinent; si l'effet net est le suivant, il est transmis par référence).
Maintenant, dans les langages modernes, les variables ont tendance à être de "types de référence" (un autre concept inventé plus tard que "passer par référence" et inspiré par lui), c'est-à-dire que les données réelles des objets sont stockées séparément quelque part (généralement, sur le tas), et seules les "références" y sont conservées dans des variables et passées en paramètres. 3
Le passage d'une telle référence relève de la valeur de passage car la valeur d' une variable est techniquement la référence elle-même, pas l'objet référé. Cependant, l'effet net sur le programme peut être le même que le passage par valeur ou le passage par référence:
Comme vous pouvez le voir, cette paire de techniques est presque la même que celles de la définition, uniquement avec un niveau d'indirection: il suffit de remplacer "variable" par "objet référencé".
Il n'y a pas de nom convenu pour eux, ce qui conduit à des explications tordues comme "appel par valeur où la valeur est une référence". En 1975, Barbara Liskov a suggéré le terme « appel par partage d'objets » (ou parfois simplement «appel par partage») bien qu'il n'ait jamais vraiment fait son chemin. De plus, aucune de ces phrases ne fait de parallèle avec la paire d'origine. Pas étonnant que les anciens termes aient été réutilisés en l'absence de mieux, ce qui a semé la confusion. 4
REMARQUE : Pendant longtemps, cette réponse disait:
Supposons que je souhaite partager une page Web avec vous. Si je vous dis l'URL, je passe par référence. Vous pouvez utiliser cette URL pour voir la même page Web que je peux voir. Si cette page est modifiée, nous voyons tous les deux les changements. Si vous supprimez l'URL, tout ce que vous faites est de détruire votre référence à cette page - vous ne supprimez pas la page elle-même.
Si j'imprime la page et vous donne l'impression, je passe par valeur. Votre page est une copie déconnectée de l'original. Vous ne verrez pas de modifications ultérieures et toutes les modifications que vous apportez (par exemple, griffonner sur votre impression) n'apparaîtront pas sur la page d'origine. Si vous détruisez l'impression, vous avez en fait détruit votre copie de l'objet - mais la page Web d'origine reste intacte.
Ceci est généralement correct, sauf le sens plus étroit de «référence» - il est à la fois temporaire et implicite (ce n'est pas nécessaire, mais être explicite et / ou persistant sont des fonctionnalités supplémentaires, ne font pas partie de la sémantique de passage par référence , comme expliqué ci-dessus). Une analogie plus étroite serait de vous donner une copie d'un document par rapport à vous invitant à travailler sur l'original.
1 À moins que vous ne programmiez en Fortran ou Visual Basic, ce n'est pas le comportement par défaut, et dans la plupart des langages en utilisation moderne, un véritable appel par référence n'est même pas possible.
2 Un bon nombre d'anciens le soutiennent aussi
3 Dans plusieurs langues modernes, tous les types sont des types de référence. Cette approche a été lancée par le langage CLU en 1975 et a depuis été adoptée par de nombreux autres langages, dont Python et Ruby. Et de nombreux autres langages utilisent une approche hybride, où certains types sont des "types de valeur" et d'autres des "types de référence" - parmi eux, C #, Java et JavaScript.
4 Il n'y a rien de mal à recycler un ancien terme approprié en soi, mais il faut en quelque sorte préciser quelle signification est utilisée à chaque fois. Ne pas le faire est exactement ce qui continue de semer la confusion.
C'est une façon de passer des arguments aux fonctions. Le passage par référence signifie que le paramètre des fonctions appelées sera le même que l'argument passé des appelants (pas la valeur, mais l'identité - la variable elle-même). Passer par valeur signifie que le paramètre des fonctions appelées sera une copie de l'argument passé des appelants. La valeur sera la même, mais l'identité - la variable - est différente. Ainsi, les modifications apportées à un paramètre par la fonction appelée dans un cas modifient l'argument passé et dans l'autre cas modifient simplement la valeur du paramètre dans la fonction appelée (qui n'est qu'une copie). En un rien de temps:
ref
utilisé lors de l'appelant et de la fonction appelée). Jon Skeet a également une belle explication à ce sujet ici .Codes
Puisque mon langage est C ++, je vais l'utiliser ici
// passes a pointer (called reference in java) to an integer
void call_by_value(int *p) { // :1
p = NULL;
}
// passes an integer
void call_by_value(int p) { // :2
p = 42;
}
// passes an integer by reference
void call_by_reference(int & p) { // :3
p = 42;
}
// this is the java style of passing references. NULL is called "null" there.
void call_by_value_special(int *p) { // :4
*p = 10; // changes what p points to ("what p references" in java)
// only changes the value of the parameter, but *not* of
// the argument passed by the caller. thus it's pass-by-value:
p = NULL;
}
int main() {
int value = 10;
int * pointer = &value;
call_by_value(pointer); // :1
assert(pointer == &value); // pointer was copied
call_by_value(value); // :2
assert(value == 10); // value was copied
call_by_reference(value); // :3
assert(value == 42); // value was passed by reference
call_by_value_special(pointer); // :4
// pointer was copied but what pointer references was changed.
assert(value == 10 && pointer == &value);
}
Et un exemple en Java ne fera pas de mal:
class Example {
int value = 0;
// similar to :4 case in the c++ example
static void accept_reference(Example e) { // :1
e.value++; // will change the referenced object
e = null; // will only change the parameter
}
// similar to the :2 case in the c++ example
static void accept_primitive(int v) { // :2
v++; // will only change the parameter
}
public static void main(String... args) {
int value = 0;
Example ref = new Example(); // reference
// note what we pass is the reference, not the object. we can't
// pass objects. The reference is copied (pass-by-value).
accept_reference(ref); // :1
assert ref != null && ref.value == 1;
// the primitive int variable is copied
accept_primitive(value); // :2
assert value == 0;
}
}
Wikipédia
http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_value
http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_reference
Ce gars le cloue à peu près:
De nombreuses réponses ici (et en particulier la réponse la plus élevée) sont en fait incorrectes, car elles ne comprennent pas ce que signifie réellement «appeler par référence». Voici ma tentative de mettre les choses au clair.
En termes simples:
En termes métaphoriques:
Notez que ces deux concepts sont complètement indépendants et orthogonaux du concept des types de référence (qui en Java sont tous les types qui sont des sous-types de Object
, et en C # tous les class
types), ou du concept des types de pointeurs comme en C (qui sont sémantiquement équivalents aux "types de référence" de Java, simplement avec une syntaxe différente).
La notion de type de référence correspond à une URL: elle est à la fois une information et une référence (un pointeur , si vous voulez) à d'autres informations. Vous pouvez avoir plusieurs copies d'une URL à différents endroits, et elles ne changent pas vers le site Web auquel elles sont toutes liées; si le site Web est mis à jour, chaque copie d'URL conduira toujours aux informations mises à jour. À l'inverse, la modification de l'URL à un seul endroit n'affectera aucune autre copie écrite de l'URL.
Notez que C ++ a une notion de "références" (par exemple int&
) qui n'est pas comme les "types de référence" de Java et C #, mais qui est comme "appel par référence". Les "types de référence" de Java et C #, et tous les types en Python, sont comme ce que C et C ++ appellent des "types de pointeurs" (par exemple int*
).
OK, voici l'explication plus longue et plus formelle.
Pour commencer, je veux souligner quelques éléments importants de la terminologie, pour aider à clarifier ma réponse et pour nous assurer que nous nous référons tous aux mêmes idées lorsque nous utilisons des mots. (Dans la pratique, je crois que la grande majorité de la confusion sur des sujets tels que ceux-ci découle de l'utilisation de mots de manière à ne pas communiquer pleinement le sens voulu.)
Pour commencer, voici un exemple dans un langage de type C d'une déclaration de fonction:
void foo(int param) { // line 1
param += 1;
}
Et voici un exemple d'appel de cette fonction:
void bar() {
int arg = 1; // line 2
foo(arg); // line 3
}
En utilisant cet exemple, je veux définir quelques bits importants de terminologie:
foo
est une fonction déclarée à la ligne 1 (Java insiste pour faire toutes les méthodes des fonctions, mais le concept est le même sans perte de généralité; C et C ++ font une distinction entre déclaration et définition que je n'entrerai pas ici)param
est un paramètre formel de foo
, également déclaré sur la ligne 1arg
est une variable , spécifiquement une variable locale de la fonction bar
, déclarée et initialisée sur la ligne 2arg
est également un argument pour une invocation spécifique de la foo
ligne 3Il y a deux ensembles de concepts très importants à distinguer ici. Le premier est la valeur par rapport à la variable :
bar
fonction ci-dessus, après la ligne int arg = 1;
, l'expression arg
a la valeur 1
.final
ou C # readonly
) ou profondément immuable (par exemple en utilisant C ++ const
).L'autre paire de concepts importants à distinguer est le paramètre par rapport à l' argument :
Dans l' appel par valeur , les paramètres formels de la fonction sont des variables qui sont nouvellement créées pour l'appel de fonction et qui sont initialisées avec les valeurs de leurs arguments.
Cela fonctionne exactement de la même manière que tout autre type de variable est initialisé avec des valeurs. Par exemple:
int arg = 1;
int another_variable = arg;
Ici arg
et another_variable
sont des variables complètement indépendantes - leurs valeurs peuvent changer indépendamment les unes des autres. Cependant, au point où another_variable
est déclaré, il est initialisé pour contenir la même valeur que celle qui arg
est - qui est 1
.
Puisqu'il s'agit de variables indépendantes, les modifications à another_variable
ne pas affecter arg
:
int arg = 1;
int another_variable = arg;
another_variable = 2;
assert arg == 1; // true
assert another_variable == 2; // true
C'est exactement la même chose que la relation entre arg
et param
dans notre exemple ci-dessus, que je vais répéter ici pour la symétrie:
void foo(int param) {
param += 1;
}
void bar() {
int arg = 1;
foo(arg);
}
C'est exactement comme si nous avions écrit le code de cette façon:
// entering function "bar" here
int arg = 1;
// entering function "foo" here
int param = arg;
param += 1;
// exiting function "foo" here
// exiting function "bar" here
C'est-à-dire que la caractéristique déterminante de ce que signifie l' appel par valeur est que l'appelé ( foo
dans ce cas) reçoit des valeurs comme arguments, mais a ses propres variables distinctes pour ces valeurs des variables de l'appelant ( bar
dans ce cas).
Pour en revenir à ma métaphore ci-dessus, si je suis bar
et vous foo
, quand je vous appelle, je vous donne un morceau de papier avec une valeur écrite dessus. Vous appelez ce morceau de papier param
. Cette valeur est une copie de la valeur que j'ai écrite dans mon cahier (mes variables locales), dans une variable que j'appelle arg
.
(En passant: selon le matériel et le système d'exploitation, il existe différentes conventions d'appel sur la façon dont vous appelez une fonction à partir d'une autre. La convention d'appel est comme si nous décidions si j'écrivais la valeur sur un morceau de mon papier, puis je vous la remettais , ou si vous avez un morceau de papier sur lequel je l'écris, ou si je l'écris sur le mur devant nous deux. C'est aussi un sujet intéressant, mais bien au-delà de la portée de cette réponse déjà longue.)
Dans l' appel par référence , les paramètres formels de la fonction sont simplement de nouveaux noms pour les mêmes variables que l'appelant fournit comme arguments.
Pour revenir à notre exemple ci-dessus, cela équivaut à:
// entering function "bar" here
int arg = 1;
// entering function "foo" here
// aha! I note that "param" is just another name for "arg"
arg /* param */ += 1;
// exiting function "foo" here
// exiting function "bar" here
Puisque param
c'est juste un autre nom pour arg
- c'est-à-dire, ils sont la même variable , les changements à param
sont reflétés dans arg
. C'est la manière fondamentale dont l'appel par référence diffère de l'appel par valeur.
Très peu de langues prennent en charge l'appel par référence, mais C ++ peut le faire comme ceci:
void foo(int& param) {
param += 1;
}
void bar() {
int arg = 1;
foo(arg);
}
Dans ce cas, param
n'a pas seulement la même valeur que arg
, elle l' est en faitarg
(juste par un nom différent) et bar
peut donc observer qu'elle arg
a été incrémentée.
Notez que ce n'est pas ainsi que fonctionnent aujourd'hui Java, JavaScript, C, Objective-C, Python ou presque tout autre langage populaire. Cela signifie que ces langues ne sont pas appelées par référence, elles sont appelées par valeur.
Si ce que vous avez est un appel par valeur , mais que la valeur réelle est un type de référence ou un type de pointeur , la "valeur" elle-même n'est pas très intéressante (par exemple, en C, c'est juste un entier d'une taille spécifique à la plate-forme) - ce qui est ce que cette valeur indique est intéressant .
Si ce que ce type de référence (c'est-à-dire, pointeur) pointe est modifiable, un effet intéressant est possible: vous pouvez modifier la valeur pointée et l'appelant peut observer les modifications de la valeur pointée, même si l'appelant ne peut pas observer modifie le pointeur lui-même.
Pour reprendre l'analogie de l'URL, le fait que je vous ai donné une copie de l'URL vers un site Web n'est pas particulièrement intéressant si la chose qui nous intéresse tous les deux est le site Web, pas l'URL. Le fait que vous gribouilliez votre copie de l'URL n'affecte pas ma copie de l'URL n'est pas une chose qui nous importe (et en fait, dans des langages comme Java et Python, "l'URL", ou la valeur du type de référence, peut ne peut pas être modifié du tout, seule la chose indiquée par lui peut).
Barbara Liskov, lorsqu'elle a inventé le langage de programmation CLU (qui avait cette sémantique), a réalisé que les termes existants "appel par valeur" et "appel par référence" n'étaient pas particulièrement utiles pour décrire la sémantique de ce nouveau langage. Elle a donc inventé un nouveau terme: appel par partage d'objets .
Lorsque je discute de langages qui sont techniquement appelés par valeur, mais où les types courants utilisés sont des types de référence ou de pointeur (c'est-à-dire: presque tous les langages de programmation modernes impératifs, orientés objet ou multi-paradigmes), je trouve que c'est beaucoup moins déroutant pour évitez simplement de parler d' appel par valeur ou d' appel par référence . Restez à appeler par partage d'objets (ou simplement appeler par objet ) et personne ne sera confus. :-)
The first is value versus variable.
The other important pair of concepts to distinguish is parameter versus argument:
Avant de comprendre les 2 termes, vous DEVEZ comprendre ce qui suit. Chaque objet, a 2 choses qui peuvent le distinguer.
Donc si tu dis employee.name = "John"
sachez qu'il y a 2 choses name
. Sa valeur qui est "John"
aussi son emplacement dans la mémoire qui est un nombre hexadécimal peut - être comme ceci: 0x7fd5d258dd00
.
Selon l'architecture du langage ou le type (classe, structure, etc.) de votre objet, vous transférez "John"
ou0x7fd5d258dd00
Passer "John"
est connu comme passer par la valeur. Passer 0x7fd5d258dd00
est connu comme passer par référence. Toute personne qui pointe vers cet emplacement mémoire aura accès à la valeur de "John"
.
Pour en savoir plus, je vous recommande de lire sur le déréférencement d'un pointeur et aussi pourquoi choisir struct (type de valeur) plutôt que classe (type de référence)
Voici un exemple:
#include <iostream>
void by_val(int arg) { arg += 2; }
void by_ref(int&arg) { arg += 2; }
int main()
{
int x = 0;
by_val(x); std::cout << x << std::endl; // prints 0
by_ref(x); std::cout << x << std::endl; // prints 2
int y = 0;
by_ref(y); std::cout << y << std::endl; // prints 2
by_val(y); std::cout << y << std::endl; // prints 2
}
y
a déjà été mis à 2 par la ligne précédente. Pourquoi reviendrait-il à 0?
Le moyen le plus simple d'obtenir cela est sur un fichier Excel. Disons par exemple que vous avez deux nombres, 5 et 2 dans les cellules A1 et B1 en conséquence, et que vous souhaitez trouver leur somme dans une troisième cellule, disons A2. Vous pouvez le faire de deux manières.
Soit en passant leurs valeurs à la cellule A2 en tapant = 5 + 2 dans cette cellule. Dans ce cas, si les valeurs des cellules A1 ou B1 changent, la somme dans A2 reste la même.
Ou en passant les «références» des cellules A1 et B1 à la cellule A2 en tapant = A1 + B1 . Dans ce cas, si les valeurs des cellules A1 ou B1 changent, la somme dans A2 change également.
Lorsque vous passez par ref, vous passez essentiellement un pointeur sur la variable. Passez par valeur vous passez une copie de la variable. Dans l'utilisation de base, cela signifie normalement que les modifications pass by ref à la variable seront considérées comme la méthode appelante et passeront par la valeur qu'elles ne connaîtront pas.
Le passage par valeur envoie une COPIE des données stockées dans la variable que vous spécifiez, le passage par référence envoie un lien direct vers la variable elle-même. Donc, si vous passez une variable par référence, puis changez la variable à l'intérieur du bloc dans lequel vous l'avez passée, la variable d'origine sera modifiée. Si vous passez simplement par valeur, la variable d'origine ne pourra pas être modifiée par le bloc dans lequel vous l'avez passée, mais vous obtiendrez une copie de ce qu'elle contenait au moment de l'appel.
Passer par valeur - La fonction copie la variable et fonctionne avec une copie (donc elle ne change rien dans la variable d'origine)
Passer par référence - La fonction utilise la variable d'origine, si vous changez la variable dans l'autre fonction, elle change également dans la variable d'origine.
Exemple (copiez et utilisez / essayez vous-même et voyez):
#include <iostream>
using namespace std;
void funct1(int a){ //pass-by-value
a = 6; //now "a" is 6 only in funct1, but not in main or anywhere else
}
void funct2(int &a){ //pass-by-reference
a = 7; //now "a" is 7 both in funct2, main and everywhere else it'll be used
}
int main()
{
int a = 5;
funct1(a);
cout<<endl<<"A is currently "<<a<<endl<<endl; //will output 5
funct2(a);
cout<<endl<<"A is currently "<<a<<endl<<endl; //will output 7
return 0;
}
Restez simple, piaule. Les murs de texte peuvent être une mauvaise habitude.
Une différence majeure entre elles est que les variables de type valeur stockent des valeurs, donc la spécification d'une variable de type valeur dans un appel de méthode transmet une copie de la valeur de cette variable à la méthode. Les variables de type référence stockent les références aux objets, donc la spécification d'une variable de type référence comme argument transmet à la méthode une copie de la référence réelle qui fait référence à l'objet. Même si la référence elle-même est passée par valeur, la méthode peut toujours utiliser la référence qu'elle reçoit pour interagir avec - et éventuellement modifier - l'objet d'origine. De même, lors du retour d'informations d'une méthode via une instruction return, la méthode retourne une copie de la valeur stockée dans une variable de type valeur ou une copie de la référence stockée dans une variable de type référence. Lorsqu'une référence est renvoyée, la méthode appelante peut utiliser cette référence pour interagir avec l'objet référencé. Donc,
En c #, pour passer une variable par référence afin que la méthode appelée puisse modifier celle-ci, C # fournit les mots clés ref et out. L'application du mot-clé ref à une déclaration de paramètre vous permet de passer une variable à une méthode par référence - la méthode appelée pourra modifier la variable d'origine dans l'appelant. Le mot clé ref est utilisé pour les variables qui ont déjà été initialisées dans la méthode d'appel. Normalement, lorsqu'un appel de méthode contient une variable non initialisée comme argument, le compilateur génère une erreur. Le fait de précéder un paramètre avec un mot clé out crée un paramètre de sortie. Cela indique au compilateur que l'argument sera transmis à la méthode appelée par référence et que la méthode appelée attribuera une valeur à la variable d'origine dans l'appelant. Si la méthode n'affecte pas de valeur au paramètre de sortie dans tous les chemins d'exécution possibles, le compilateur génère une erreur. Cela empêche également le compilateur de générer un message d'erreur pour une variable non initialisée transmise en tant qu'argument à une méthode. Une méthode ne peut renvoyer qu'une seule valeur à son appelant via une instruction return, mais peut renvoyer de nombreuses valeurs en spécifiant plusieurs paramètres de sortie (ref et / ou out).
voir la discussion c # et les exemples ici lien texte
Exemples:
class Dog
{
public:
barkAt( const std::string& pOtherDog ); // const reference
barkAt( std::string pOtherDog ); // value
};
const &
est généralement le meilleur. Vous n'encourez pas la pénalité de construction et de destruction. Si la référence n'est pas constante, votre interface suggère qu'elle changera les données transmises.
Si vous ne voulez pas modifier la valeur de la variable d'origine après l'avoir passée dans une fonction, la fonction doit être construite avec un paramètre " passe par valeur ".
La fonction n'aura alors que la valeur mais pas l'adresse de la variable passée. Sans l'adresse de la variable, le code à l'intérieur de la fonction ne peut pas modifier la valeur de la variable comme vu de l'extérieur de la fonction.
Mais si vous souhaitez donner à la fonction la possibilité de modifier la valeur de la variable vue de l'extérieur, vous devez utiliser le passage par référence . Comme la valeur et l'adresse (référence) sont transmises et disponibles dans la fonction.
passer par valeur signifie comment passer de la valeur à une fonction en utilisant des arguments. en passant par valeur, nous copions les données stockées dans la variable que nous spécifions et c'est plus lent que de passer par référence car les données sont copiées. Si nous modifions les données copiées, les données d'origine ne sont pas affectées. En passant par référence ou par adresse, nous envoyons un lien direct vers la variable elle-même. ou en passant le pointeur sur une variable. c'est plus rapide car moins de temps est consommé
Voici un exemple qui montre les différences entre passer par valeur - valeur du pointeur - référence :
void swap_by_value(int a, int b){
int temp;
temp = a;
a = b;
b = temp;
}
void swap_by_pointer(int *a, int *b){
int temp;
temp = *a;
*a = *b;
*b = temp;
}
void swap_by_reference(int &a, int &b){
int temp;
temp = a;
a = b;
b = temp;
}
int main(void){
int arg1 = 1, arg2 = 2;
swap_by_value(arg1, arg2);
cout << arg1 << " " << arg2 << endl; //prints 1 2
swap_by_pointer(&arg1, &arg2);
cout << arg1 << " " << arg2 << endl; //prints 2 1
arg1 = 1; //reset values
arg2 = 2;
swap_by_reference(arg1, arg2);
cout << arg1 << " " << arg2 << endl; //prints 2 1
}
La méthode du «passage par référence» présente une limitation importante . Si un paramètre est déclaré transmis par référence (il est donc précédé du signe &), son paramètre réel correspondant doit être une variable .
Un paramètre réel faisant référence au paramètre formel «passé par valeur» peut être une expression en général, il est donc permis d'utiliser non seulement une variable mais aussi un résultat d'invocation de fonction littérale ou même de fonction.
La fonction n'est pas en mesure de placer une valeur dans autre chose qu'une variable. Il ne peut pas affecter une nouvelle valeur à un littéral ni forcer une expression à changer son résultat.
PS: Vous pouvez également vérifier la réponse de Dylan Beattie dans le fil de discussion actuel qui l'explique en termes simples.