Speichervariable zu Speichervariable zuweisen, was passiert?

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?

swird bis addStructzur Rückkehr nicht freigegeben. Es kann hilfreich sein, Stack-Frames oder Aktivierungsdatensätze zu verstehen

Antworten (2)

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.

Danke für den Hinweis, bearbeitet. Sicher, schon probiert? Das ist für mich am offensichtlichsten, aber ich wollte eine Bestätigung
Mein erster Teil, ja. Es kopiert das Objekt im Speicher in den Speicher. Sie können dies in Remix testen, indem Sie eine getStruct-Funktion hinzufügen, die die Daten von structs[msg.sender] aus einer anderen Transaktion abruft. Wenn sie nicht in den Speicher kopiert wurden, würden diese Daten nicht existieren. Ich habe mich bei meinem zweiten Teil geirrt, da @LibertyLocked zu Recht sagte, dass es einen Kompilierungsfehler geben würde. Ich habe meine Antwort auch aktualisiert.

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:

  • updateStructserwartet eine Strukturinstanz aus dem Speicher, aber Sie übergeben ihr eine Strukturinstanz im Speicher.
  • Es gibt für Solidity keine Möglichkeit, herauszufinden, wo die sIn addStructgespeichert werden sollen.
  • Wenn Sie S memory sInstancein Ihre haben, wird updateStructIhre 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 ?).supdateStructssaddStructaddStructupdateStruct

Um Ihre Frage zu beantworten, müssen Sie in Ihrem Beispiel memoryanstelle von storage. Tatsächlich ist es implizit memoryin Funktionsargumenten enthalten.

OK, um es zusammenzufassen: Beim S memory s = S({a: _a, b: _b});Speicher wird eine Variable im Bereich von erstellt addStruct, dann wird updateStructs(s);der Wert von sin den Stapelrahmen von kopiert updateStructsund dann swird der vom Stapelrahmen in den Speicher von kopiert structs[msg.sender] = sInstance;, richtig? Meine Frage war, was an diesem Ort im Lager sein wird.
Es gibt nur einen Speicherort und das ist structs[msg.sender]. Es wird nur in geändert updateStructs. storageSchlüsselwort bedeutet einen Verweis auf den Speicherort
Wenn Sie also eine Referenztypvariable, die sich im Funktionsstapel befindet, einer Variablen zuweisen, die sich im Speicher befindet, wird diese Variable in den Speicher kopiert?
Die Referenz kann kopiert werden, aber der Speicher selbst wird nie geändert, bis Sie in die Referenz schreiben
Ich denke, es fällt uns schwer, uns zu verstehen :) So verstehe ich es: Wenn Sie darauf übergeben s, updateStructswerden Bytes auf dem Stapel zugewiesen und sauf diese Bytes verwiesen. Wenn du das tust, structs[msg.sender] = sInstancewas passiert? Wenn die Referenz skopiert 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.