Ich weiß nicht, warum niemand diese Frage stellt (ich habe meine Hausaufgaben gemacht und tonnenweise gegoogelt, um eine Antwort zu finden), aber es fällt mir schwer zu verstehen, wie Funktionsmodifikatoren tatsächlich funktionieren.
Sicher, es ist trivial, wenn Sie nur einen Modifikator verwenden, oder wenn Sie die _
Notation immer am Ende verwenden. Aber ich stoße auf Code, der in etwa so aussieht:
modifier modA {
// verify something
_;
// verify something
_;
}
modifier modB {
// verify something
_;
// verify something
_;
}
modifier modC {
// verify something
_;
// verify something
_;
}
function Fun() modA modB modC {
// Do something
}
Dann wird mir endlich klar, dass ich keine Ahnung hatte, was darunter vor sich geht.
Wie soll das im obigen Fall funktionieren? Ein Blick in die Dokumentation hilft nicht wirklich weiter, da dort nur steht, dass die Modifikatoren einfach das _
durch den Funktionscode ersetzen. Aber was ist, wenn es mehrere davon gibt?
Wenn wir also von modA
zu gehen modB
, wird das _
durch den nächsten Modifikator ersetzt? Was meinen sie mit "durch die ursprüngliche Funktion ersetzt werden"?
Ich denke, dass ein guter Weg, um zu verstehen, was passiert, darin besteht, damit zu experimentieren
Ich habe diesen Vertrag in Remix erstellt, um einige meiner Annahmen darüber zu testen/zu beweisen, was mit Modifikatoren passiert:
pragma solidity ^0.4.18;
contract modifierTest {
uint public modState1;
uint public modState2;
uint public modState3;
modifier modA() {
modState1 = modState1 + 1;
_;
}
modifier modB() {
modState2 = modState2 + 1;
_;
modState2 = modState2 + 1;
_;
}
function func() public modA modB {
modState3 = modState3 + 1;
}
}
Anfänglich werden alle Zustandsvariablen des Vertrags auf 0 gesetzt/standardmäßig auf 0 gesetzt.
Nachdem wir die Funktion func ausgeführt und die Zustandsvariablen untersucht haben, sehen wir das folgende Ergebnis:
modState1 - uint256: 1
modState2 - uint256: 2
modState3 - uint256: 2
Daraus können wir verstehen, dass die ; im Modifikator *modA* durch den Code des Modifikators *modB* ersetzt wurde und dass die * ;*s im Hauptteil des Modifikators modB durch den Code der func - Funktion ersetzt wurden.
Wenn wir also von modA zu modB gehen, wird das _ durch den nächsten Modifikator ersetzt? Was meinen sie mit "durch die ursprüngliche Funktion ersetzt werden"?
Hoffentlich zeigt dieses Beispiel, wie das _ durch den nächsten Modifikator ersetzt wird und dass das _ des letzten Modifikators durch den Code der Funktion ersetzt wird.
Angenommen, eine vertragsweite Variable „a“ mit einem Wert von „0“ und eine Funktion F mit einem Modifikator M:
function F() M() {
a = 1;
}
modifier M() {
if (a == 1) throw;
_
}
das wird nicht werfen. Aber diese Version:
modifier M() {
_
if (a == 1) throw;
}
wird werfen. Stellen Sie sich Modifikatoren als Codeersatz (Vorkompilierung in C++-Begriffen) im Gegensatz zu "Aufrufen" vor. Modifikatoren sind keine Funktionen. Es ist genau so, als ob die Funktion F in jedem Fall so aussehen würde, was, wenn Sie davon ausgehen, dass 'a' einen Wert von '0' hat, um zu starten, zwei unterschiedliche Verhaltensweisen hat:
function F() {
if (a == 1) throw;
a = 1;
}
und
function F() {
a = 1;
if (a == 1) throw;
}
Um es herauszufinden, egal wie kompliziert, kopieren Sie einfach den Modifikatorcode an die richtige Stelle in der zu ändernden Funktion. Möglicherweise müssen Sie viele Ebenen tief kopieren, aber das ist es, was der Precompiler tut.
Ich bin überrascht, zwei _
in Ihren Beispielen zu sehen. Ich wusste nicht, dass du das kannst. Es scheint mir eine sehr schlechte Praxis zu sein, _
zweimal in einem Modifikator zu verwenden. Es macht den Code enorm schwer konzeptionell zu verstehen. Zumindest tut es das für mich.
_
s haben. Hier ist einer: ethereum.stackexchange.com/a/5864/21958 - Ich denke auch, dass Sie verstehen, was Sie sagen, aber könnten Sie die Antwort erläutern, um sicherzugehen? Wie ich verstanden habe, sagen Sie, dass die Funktion F () nicht ausgeführt wird, bis sie alle Modifikatoren M1 (), M2 (), M3 () nacheinander durchläuft, wobei M1 () zuerst F () ersetzt. Ersetzen Sie dann das Ergebnis durch M2() und so weiter. Und erst wenn es den letzten Modifikator erreicht, führt es die Funktion tatsächlich aus?
Jack O'Neill
func
zweimal aufgerufen wird, weil Sie mehrere_;
drinmodB
haben und nicht, weil es mehrere Modifikatoren gibt.