Haftungsausschluss: Diese Antwort kann nicht völlig SFW als S-Ausdrücke, die für in der Nähe von allen Objekten in R abgekürzt sexp (Yep, S-expression, wobei der Strich die häufigste Art ist, ist nicht, wo Sie dachten,). Jetzt als SALT 'N' PEPA hatte singen: lassen Sie uns über sexp sprechen!
TL; DR: Eine Umgebung, in ihm gespeichert ist, ist Elternumgebung als Zeiger, die Variable zu kopieren, darauf zuzugreifen, vervielfältigen nur den Zeiger und immer noch das gleiche Objekt anvisieren.
Ich habe einige auf die Ursache zu graben, Hauptgrund ist, was eine Umwelt ist, oder in der Tat, wie es in ihm gespeichert ist, ist Umwelt Eltern. Mal sehen, new.env
:
> new.env
function (hash = TRUE, parent = parent.frame(), size = 29L)
.Internal(new.env(hash, parent, size))
<bytecode: 0x0000000005972428>
<environment: namespace:base>
Ok, Zeit zum Quellcode gehen, in names.c
:
{"new.env", do_newenv, 0, 11, 3, {PP_FUNCALL, PREC_FN, 0}},
Suche do_newenv
bringen uns builtin.c
die Return (ich hier eine Verknüpfung nahm, aber lassen Sie uns dies nicht halten zu lang):
ans = NewEnvironment(R_NilValue, R_NilValue, enclos);
Diese NewEnvironment
definiert here in memory.c
und die comm ents darüber uns einen Hinweis geben, was los ist:
Erstellen Sie eine Umgebung „rho“ mit einem Rahmen erhalten durch die Erweiterung von
die Variablennamen durch die Tags auf „Namensliste“ mit den angegebenen Werte Paarung gegeben durch die Elemente der "Werteliste".
Der Code auf sich selbst ist nicht so einfach zu folgen:
zu einer Variablendefinition in globalen Umfeld
SEXP NewEnvironment(SEXP namelist, SEXP valuelist, SEXP rho)
{
SEXP v, n, newrho;
if (FORCE_GC || NO_FREE_NODES()) {
PROTECT(namelist);
PROTECT(valuelist);
PROTECT(rho);
R_gc_internal(0);
UNPROTECT(3);
if (NO_FREE_NODES())
mem_err_cons();
}
GET_FREE_NODE(newrho);
newrho->sxpinfo = UnmarkedNodeTemplate.sxpinfo;
INIT_REFCNT(newrho);
TYPEOF(newrho) = ENVSXP;
FRAME(newrho) = valuelist;
ENCLOS(newrho) = CHK(rho);
HASHTAB(newrho) = R_NilValue;
ATTRIB(newrho) = R_NilValue;
v = CHK(valuelist);
n = CHK(namelist);
while (v != R_NilValue && n != R_NilValue) {
SET_TAG(v, TAG(n));
v = CDR(v);
n = CDR(n);
}
return (newrho);
}
Vergleich (exemple für geistige Gesundheit des Lesers Geist gewählt) durch gsetVar
:
void gsetVar(SEXP symbol, SEXP value, SEXP rho)
{
if (FRAME_IS_LOCKED(rho)) {
if(SYMVALUE(symbol) == R_UnboundValue)
error(_("cannot add binding of '%s' to the base environment"),
CHAR(PRINTNAME(symbol)));
}
#ifdef USE_GLOBAL_CACHE
R_FlushGlobalCache(symbol);
#endif
SET_SYMBOL_BINDING_VALUE(symbol, value);
}
Wir können den "Wert" sehen, der von der Elternumgebung zugänglich ist, ist die neue Umgebungsadresse, gegeben durch die GET_FREE_NODE
auf Elternumwelt (ich bin unsicher, dass ich hier klar bin, aber ich fand kein richtiges p rasing).
Also mit der Tatsache <-
ist definiert als x <- value
Wir kopieren einen Zeiger, wir haben mehrere unabhängige Variablen, die alle auf das gleiche Objekt zeigen.
Das Aktualisieren des Objekts mit einer Referenz aktualisiert das einzige im Speicher vorhandene Objekt.
SEXP
Ständer für S-Expression nach verschiedenen literrature und ist in erster Linie ein Zeiger in C.
Von Kommentaren,
Für eine schöne Erklärung der Referenz-Semantik von Umgebungen siehe Hadley http://adv-r.had.co.nz/Environments.html. -> "Neben dem Power-Scoping sind Umgebungen auch eigenständige Datenstrukturen, da sie Referenzsemantik haben. Im Gegensatz zu den meisten Objekten in R wird bei der Änderung einer Umgebung keine Kopie erstellt." – cryo111