Ich habe einen Vertrag geschrieben, der die Zuordnungsspeichervariablen A & B enthält. Diese Variablen werden mit einigen Werten im Konstruktor initialisiert. Eine Methode getBalance gibt den Kontostand von Mapping A & B zurück.
In der Methode habe ich eine andere Zuordnung deklariert - ich dachte, dass dies zu einem Kompilierungsfehler führen würde (da die Zuordnung nur für die Speicherung zulässig ist). Stattdessen führte es zu einem seltsamen Verhalten - es scheint, dass die neue lokale Zuordnung die Zuordnung A überschreibt.
Ergebnis ohne lokales Mapping (100, 200) wie erwartet Ergebnis mit lokalem Mapping (500, 200) <<< Warum?
/** Getestet in Truffle/TestRPC **/
contract Mapping {
mapping(address => uint) balancesA;
mapping(address => uint) balancesB;
function Mapping() {
// constructor
balancesA[msg.sender] = 100;
balancesB[msg.sender] = 200;
}
function getBalance(address addr) returns(uint, uint) {
// If these 2 lines are commented then behavior is as expected
mapping(address => uint) balancers;
balancers[msg.sender] = 500;
return (balancesA[addr], balancesB[addr]);
}
}
Habe hier ein Issue eröffnet, github, ethereum, solidity, issue 1731: https://github.com/ethereum/solidity/issues/1731
Wenn ich ihren Prozess richtig verstehe, wird die ursprüngliche Ausgabe 1731 durch Ausgabe 1737 geschlossen, die jetzt zusammengeführt wird. Möglicherweise gibt der Compiler in Zukunft einen Fehler für solche Dinge aus.
Beide Daumen hoch für die Entwickler!
Abgesehen davon ist es ein Fehler in der Solidität (da es bemerken sollte, dass eine nicht initialisierte Variable verwendet wird), es ist erwähnenswert, dass der Code auch nicht korrekt ist.
Das Problem ist, dass mapping(address => uint) balancers
im Funktionskörper keine neue Zuordnung zugewiesen wird. Es führt nur eine Variable ein balancers
, die auf eine (an anderer Stelle zugewiesene) Zuordnung verweisen kann.
Im Beispiel balancers
wird nicht initialisiert und zufällig referenziert balancesA
. Daher das unerwartete Verhalten.
Aus Solidity-Dokumenten :
Zuordnungen sind nur für Zustandsvariablen (oder als Speicherreferenztypen in internen Funktionen) zulässig.
Ich fürchte, das ist kein Bug. Ich stimme sehr zu, dass es ein Problem ist und eine riesige Falle darstellt.
Bitte sehen Sie sich die Dokumentation hier an: https://solidity.readthedocs.io/en/v0.4.9/types.html#data-location
Wie in der Antwort von Max Taldykin erwähnt: Indem Sie die lokalen Variablenbalancer innerhalb der Funktion deklarieren, erstellen Sie lediglich eine neue Referenz mit einem anderen Namen, die auf eine Zuordnung im Speicher verweist. Ich schätze, es verlinkt nur auf das erste, das es auf globaler Ebene deklariert findet.
Das Deklarieren der lokalen Variablen als Speicher würde das Überschreiben verhindern.
mapping(address => uint) memory balancers;
Um es klar zu sagen: Dieses Problem gilt nur für Nicht-Primitive (Strukturen, Zuordnungen und Arrays), wenn sie lokal innerhalb von Funktionen deklariert werden, da ihr Standardspeicherort der Speicher ist , wie in dem oben verlinkten Dokument erläutert!
Rob Hitchens
Radmen
Xavier Leprêtre B9lab
ACloudFan
Rob Hitchens
o0ragman0o
returns (uint, uint)
eher als genannt werden, oderbalanceA = balancesA[addr];
etc