Definition:
mapping(address => data) clusterContract;
struct data { //defined inside a Library.
mapping(address => Library.Struct[]) my_status;
}
data list;
clusterContract[id] = list;
Verwendung:
clusterContract[msg.sender].my_status[id].push( Library.Struct({ status: status_ }));
delete clusterContract[msg.sender].my_status; //<=error occurs.
Fehler tritt auf:
Error: Unary operator delete cannot be applied to type
mapping(address => struct ReceiptLib.Status storage ref[] storage ref)
E delete clusterContract[msg.sender].my_status;
Andererseits: delete clusterContract[msg.sender].my_status[id]
funktioniert.
=> Vervollständigt delete clusterContract[msg.sender]
removes(initialize to 0) my_status
auch das Array von?
[F] Wie kann ich mich delete
für den vollständigen Speicher ref[] bewerben? oder muss ich ref [] (die ids verfolgen) iterieren und lösche einzeln anwenden, wie im beispiel gezeigt?
Beispiel:
for(int i=0;i<storedIDs.size();i++)
delete clusterContract[msg.sender].my_status[storedIDs[i]];
Vielen Dank für Ihre wertvolle Zeit und Hilfe.
Das Löschen von Daten gibt Zustandsraum auf Clients frei State Tree Pruning
und sollte nach Möglichkeit durchgeführt werden, wenn sie nicht mehr benötigt werden.
Zuordnungen können jedoch nicht einfach in einem einzigen Vorgang gelöscht werden, da der Vertrag selbst nicht weiß, wo sich die Daten in der staatlichen Adresse befinden. Dazu muss der Schlüssel bereitgestellt werden, um die einzeln zugeordneten Elemente zu löschen.
Unbegrenzte Arrays wie uint[]
bytes
usw. können in einem solidity
Vorgang gelöscht werden, jedoch muss die EVM iterativ jeden Steckplatz einzeln löschen. Es muss darauf geachtet werden, dass solche Arrays nicht zu groß werden, da ein zukünftiger Massenlöschvorgang das Blockgaslimit erschöpfen und Ihren Vertrag brechen könnte. Die Lektion hier ist, dass Ihre Garbage Collection auch atomar sein sollte.
Das Speichern neuer Daten kostet 20.000 pro Slot, während das Überschreiben von Daten nur 5.000 kostet. Das Löschen von Daten kostet ebenfalls 5.000 pro Slot, bringt aber am Ende Ihres Anrufs eine Rückerstattung von 15.000 Benzin pro Slot.
Was Rob vorgeschlagen hat, ist eine gute Praxis mit Arrays, da Sie neu initialisierten Speicher einfach wiederverwenden können, indem Sie ihn length
auf 0 setzen. Sie verwenden jedoch keine Arrays, sondern Zuordnungen, was ein ganz anderes Ballspiel ist.
Also, von Ihren Codefragmenten ...
struct data {
//defined inside a Library.
mapping(address => Library.Struct[]) my_status;
}
mapping(address => data) clusterContract;
data list;
clusterContract[id] = list;
...
clusterContract[msg.sender].my_status[id].push( Library.Struct({ status: status_ }));
wenn du es versuchst:
delete clusterContract[msg.sender].my_status; //<=error occurs.
Sie versuchen, ein gesamtes Mapping auf einmal zu löschen, weil .mystatus
es wie folgt definiert ist:
mapping(address => Library.Struct[]) my_status;
aber ein Mapping selbst kann nicht gelöscht werden, nur seine Elemente.
Insbesondere wenn ich mit Mappings von Strukturen arbeite, schreibe ich Dekonstruktoren, um sie zu bereinigen. Also sowas wie:
function destroy(id) internal
{
delete clusterContract[msg.sender].my_status[storedIDs[id]];
}
Versuchen Sie jedoch erneut, auf atomare Operationen mit bekannten Lebenszyklen hinzuarbeiten, anstatt sich auf teure und unordentliche Massenbereinigungen verlassen zu müssen.
Löschen macht nicht viel mit den zugrunde liegenden Daten, da es sich um ein reines Anhänge-Speichersystem handelt. Egal was wir tun, die Daten sind immer noch in einem früheren Weltzustand vorhanden.
Da Sie alle Elemente im Array auf einmal entfernen möchten:
pragma solidity ^0.4.6;
contract NullifyArray {
address[] public status;
function pushArray(address data)
public
returns(uint arrayLength)
{
return status.push(data);
}
function getArrayLength()
public
constant
returns (uint arrayLength)
{
return status.length;
}
function nullifyArray()
public
returns(uint arrayLength)
{
status.length=0;
return status.length;
}
}
Dadurch bleibt die Grundstruktur bestehen, dh die Struktur hat immer noch ein Array, aber seine Länge ist 0 und der öffentliche Getter kann auf keine Elemente zugreifen. Es hat nichts dazu beigetragen, die Daten zu löschen, die in der Kette vorhanden sind, aber sie sind logischerweise verschwunden.
Wenn Sie wählerisch sein müssen, welche Array-Zeilen entfernt werden sollen, schlage ich hier das Muster Mapped Structs with Delete-enabled Index vor: Gibt es gut gelöste und einfache Speichermuster für Solidity?
Ich hoffe es hilft.
Alper
throw
für den Benutzer tun, der auf die Daten zugreifen möchte? Die Sache ist, dass es einen Löschvorgang geben könnte und über dieselbe ID neu erstellt werden kann. @Rob HitchensAlper
Rob Hitchens
Alper
status.length = 0
den Job machen.Rob Hitchens
Alper
my_status[id].length
. Da ich die Schlüssel nicht kenne, muss ich sie auch speichern, um wieder auf sie zugreifen zu können, um ihre Länge auf 0 zu initialisieren. @Rob HitchensRob Hitchens
Alper
Rob Hitchens
Alper
o0ragman0o
State Tree Pruning
und sollte nach Möglichkeit durchgeführt werden, um Speicherplatz zurückzugewinnen.Rob Hitchens
o0ragman0o