Wie man aus einem Speicherarray in Solidity herausspringt (die Länge verringert).

Ich habe eine Funktion, die ein Adress-Array aus einem anderen Vertrag abruft, msg.sender bedingt aus dem Array löscht und dann das neue Array wieder in diesem Vertrag speichert.

Da sich das Array backerList im Speicher befindet, kann ich das nicht tunbackerList.length--;

Aber ich kann backerList nicht als Speicher-Array deklarieren, da das Speicher-Array nicht in ein Speicher-Array konvertiert werden kann.

Ich stecke hier fest, was soll ich tun?

 address[] memory backerList = syndicate.getBackerList();

 if(syndicate.individualTotalBacking(msg.sender) == 0){

        uint index;

        for(uint i=0; i<backerList.length; i++){
            if (backerList[i] == msg.sender){
                index = i;
            }

        //shifting array

            for(uint k=index; k<backerList.length-1; k++){
                backerList[k]=backerList[k+1];
            }

        }

        backerList.length--;
        syndicate.setBackerList(backerList);
    } else {}
Was ist die Funktionssignatur von setBackerList?
setBackerList übergibt grundsätzlich backerList[ ] an einen anderen Vertrag namens syndicate. Ich denke nicht, dass dies das Problem ist, um ehrlich zu sein.
Was ich zu fragen versuche, ist, ist der Parametertyp setBackerListeines address[] memory?
Guter Punkt, es wurde gerade als diese Funktion deklariert setBackerList(address[] newBackerList) public { ... }

Antworten (2)

backerList.length--;Hier ist eine Möglichkeit, dies address[] memory backerListmithilfe der Inline-Assemblierung zu tun:

assembly { mstore(backerList, sub(mload(backerList), 1)) }

Einige wichtige Punkte, an die Sie sich erinnern sollten:

  • Stellen Sie sicher, dass dieser Assembler-Code niemals ausgeführt wird backerList.length == 0(erlauben Sie nicht, dass die Array-Länge unterläuft).

  • Versuchen Sie nicht, dies zu verwenden, um die Größe eines Arrays zu erhöhen (indem Sie es durch ersetzen sub) add.

  • Verwenden Sie es nur für Variablen mit einem Typ wie ...[] memory(verwenden Sie es beispielsweise nicht für a address[10] memoryoder address)

Haftungsausschluss: Die Verwendung der Inline-Assemblierung wird normalerweise nicht empfohlen. Verwenden Sie es mit Vorsicht und auf eigene Gefahr :)

erstaunlich und beängstigend, wie riskant ist es für mich, es zu benutzen? das wäre für mich eine saubere lösung.
@ RickChen Ich empfehle auf jeden Fall, es gründlich zu testen. Die wichtigsten Bedenken sind: Verwenden Sie es nicht auf leeren Arrays. Verwenden Sie es nur für Variablen mit einem Typ wie ...[] memory.
Gibt es ein Update im Jahr 2022 oder ist dies immer noch die einzige Möglichkeit, dies zu tun?
Warum nicht add verwenden, um die Größe des Arrays zu erhöhen? Scheint, als hätte ich es erfolgreich verwendet, um auf ein Speicherarray zu "pushen". Hat zumindest im Test funktioniert. Vielen Dank für diesen Kommentar übrigens, dass eine Zeile von Yul zum 'Pop' (und anscheinend Push) in Speicherarrays eine große Hilfe war
@RyanSea Sie können sich vorstellen, dass der EVM-Speicher eine uint8[2**64-1]. Wenn Sie uint[] memory a = new uint()[10];den Compiler ausführen, weist er einen Teil dieses Arrays zu, um a. Der Compiler kann entscheiden , den Speicher direkt danach afür andere Zwecke zu verwenden ( b) , da er zu Recht davon ausgeht , dass kein Sprachfeature wachsen kann a. Wenn Sie zum Vergrößern die Inline-Assemblierung verwenden, aüberschreiben Sie b. Wenn ein anderer Code in schreibt b, überschreibt er den erweiterten Teil von a. Schlechte Zeiten. Es kann „funktionieren“, weil es kein gibt b, aber es funktioniert nicht , weil Sie alle Sicherheitsgarantien verloren haben.

Ja, Sie haben Recht, Sie können die Größe des Speicherarrays nicht explizit reduzieren, es gilt nur für Speicherarrays. Aber Sie können den Löschoperator verwenden, um den Speicher zu löschen, wodurch Ihr Gas gespart wird.

Die Größe des Arrays ändert sich jedoch nicht, sie bleibt gleich. Sie müssen eine zusätzliche Variable erstellen, um die Größe des Arrays zu verfolgen.