Ich bin gespannt, was passiert, wenn Sie versuchen, Folgendes zu tun:
contract C {
Struct S {
uint a;
uint b;
}
mapping(address => s) structs;
function updateStructs(S sInstance) private {
structs[msg.sender] = sInstance;
}
function addStruct (uint _a, uint _b) payable {
S memory s = S({a: _a, b: _b});
updateStructs(s);
}
}
Wie ich verstanden habe, wie Variablen funktionieren, erstellt die addStruct eine Speichervariable, die nur einen Funktionsumfang hat und deren Zuordnung aufgehoben wird, sobald diese Transaktion/Nachricht verarbeitet wird. Was bleibt also drin, structs[msg.sender]
nachdem addStruct aufgerufen wurde? Wird updateStructs(S sInstance)
sich updateStructs(S storage sInstance)
etwas ändern?
Wenn Sie eine Speichervariable im Speicher speichern, wird das Objekt einfach in den Speicher kopiert.
Die Verwendung des Schlüsselworts storage in updateStructs wird eigentlich nichts bewirken. Strukturen und Arrays in Funktionen sind standardmäßig Speichervariablen, sodass das Speicherobjekt tatsächlich direkt in den Speicher kopiert wird, wenn Sie updateStructs ohne das Speicherschlüsselwort aufrufen.
Edit: Ich stehe korrigiert. @LibertyLocked hat in ihrer Antwort Recht, wo sie sagen, dass Sie nicht implizit vom Speicher in den Speicher konvertieren können. Wenn Sie also das Speicherschlüsselwort zum Argument hinzufügen, schlägt die Kompilierung fehl.
Wenn Sie in Ihrem Beispiel Ihren Code so ändern würden, dass er so aussieht
function updateStructs(S storage sInstance) private {
structs[msg.sender] = sInstance;
}
function addStruct (uint _a, uint _b) payable {
S memory s = S({a: _a, b: _b});
updateStructs(s);
}
Der Code wird aus folgenden Gründen nicht kompiliert:
updateStructs
erwartet eine Strukturinstanz aus dem Speicher, aber Sie übergeben ihr eine Strukturinstanz im Speicher.s
In addStruct
gespeichert werden sollen.S memory sInstance
in Ihre haben, wird updateStruct
Ihre in den Stapelrahmen von kopiert . Außerdem wird die Zuordnung von in nicht aufgehoben, bis Sie von zurückkehren (wie würde die Funktion sonst weiter ausgeführt werden, wenn sie von zurückkehrt ?).s
updateStructs
s
addStruct
addStruct
updateStruct
Um Ihre Frage zu beantworten, müssen Sie in Ihrem Beispiel memory
anstelle von storage
. Tatsächlich ist es implizit memory
in Funktionsargumenten enthalten.
S memory s = S({a: _a, b: _b});
Speicher wird eine Variable im Bereich von erstellt addStruct
, dann wird updateStructs(s);
der Wert von s
in den Stapelrahmen von kopiert updateStructs
und dann s
wird der vom Stapelrahmen in den Speicher von kopiert structs[msg.sender] = sInstance;
, richtig? Meine Frage war, was an diesem Ort im Lager sein wird.structs[msg.sender]
. Es wird nur in geändert updateStructs
. storage
Schlüsselwort bedeutet einen Verweis auf den Speicherorts
, updateStructs
werden Bytes auf dem Stapel zugewiesen und s
auf diese Bytes verwiesen. Wenn du das tust, structs[msg.sender] = sInstance
was passiert? Wenn die Referenz s
kopiert wird, ist dies nicht sinnvoll, da die dem Stack zugewiesenen Bytes nur im Funktionsbereich gültig sind und structs[msg.sender]
je nach Knoten, auf dem sie ausgeführt wird, auf zufällige Bytes zeigen. Wenn die dem Stack zugewiesenen Bytes kopiert werden, ist structs[msg.sender]
es in Ordnung, aber ich habe noch keine Bestätigung dazu von Ihren Antworten erhalten.
libertylocked
s
wird bisaddStruct
zur Rückkehr nicht freigegeben. Es kann hilfreich sein, Stack-Frames oder Aktivierungsdatensätze zu verstehen