Meine Vermutung: Es gibt das Konzept von address
in Solidity, aber sie repräsentieren contract
s. Verträge können Fallback-Funktionen haben, aber ich glaube nicht, dass Sie ihnen Parameter geben können. Denken Sie daran, die Funktion als Parameter per Adresse zu übergeben, wie Sie es in C tun würden.
Gibt es einen legitimen Weg, Funktionen als Parameter zu übergeben, oder gibt es einen Hacky-Weg, wenn nicht?
Wenn ja, wie? Und wenn nicht, warum nicht?
Funktionen (auch bekannt als Methoden) werden von der ABI spezifiziert und haben eine Methoden-ID, die die ersten 4 Bytes von sha3 (Keccak-256) der Signatur der Methode sind.
Hier ist ein Beispiel für den Aufruf someFunction
von contract
:contract.call(bytes4(sha3("someFunction()")))
Hier ist eine getestete Funktion mit Übergabe von a methodId
als Parameter:
contract C1 {
uint public _n; // public just for easy inspection in Solidity Browser
function foo(uint n) returns(uint) {
_n = n;
return _n;
}
function invoke(bytes4 methodId, uint n) returns(bool) {
return this.call(methodId, n);
}
}
Testen Sie es im Solidity Browser , indem Sie "0x2fbebd38", 9
als Parameter to verwenden invoke
, und sehen Sie dann, dass es _n
gleich ist 9
.
Anmerkungen:
0x2fbebd38
ist das Ergebnis von bytes4(sha3("foo(uint256)"))
(vergessen Sie nicht die Notwendigkeit, kanonische Typen zu verwenden, in diesem Fall uint256
gemäß ABI. )
Rückgabewerte von call und callcode sind boolesch, entweder der Aufruf war erfolgreich oder der Aufruf ist fehlgeschlagen. Es ist nicht möglich, einen Wert aus dem Aufruf zurückzugeben, da dies erfordern würde, dass der Vertrag den Rückgabetyp vorher kennt.
Um die Antwort von Nick Johnson zu ergänzen, können Sie mit Funktionstypen in neueren Versionen von Solidity jetzt Funktionszeiger beschreiben:
http://solidity.readthedocs.io/en/latest/types.html#function-types
Funktionstypen sind die Typen von Funktionen. Variablen des Funktionstyps können von Funktionen zugewiesen werden, und Funktionsparameter des Funktionstyps können verwendet werden, um Funktionen an Funktionsaufrufe zu übergeben und Funktionen von Funktionsaufrufen zurückzugeben. Funktionstypen gibt es in zwei Varianten – interne und externe Funktionen
Die Antwort von eth gilt für externe Funktionsaufrufe (zwischen Verträgen oder durch Verwendung der externen Schnittstelle zum Aufrufen Ihres eigenen Vertrags); hier werde ich versuchen, für interne Funktionsaufrufe zu antworten.
Solidity bietet derzeit keine Syntax zum Beschreiben des Typs eines Funktionszeigers, sodass Sie sie nicht als Argumente oder Rückgabewerte verwenden können. Funktionen sind jedoch erstklassig und können mit var
; Variablen zugewiesen werden. Hier ist das Beispiel aus dem Solidity-Benutzerhandbuch :
contract FunctionSelector {
function select(bool useB, uint x) returns (uint z) {
var f = a;
if (useB) f = b;
return f(x);
}
function a(uint x) returns (uint z) {
return x * x;
}
function b(uint x) returns (uint z) {
return 2 * x;
}
}
Für alle, die von Google kommen und nach einem schnellen Beispiel suchen, wie eine Funktion als Parameter übergeben wird, sehen Sie sich den folgenden Codeauszug an (Quelle https://docs.soliditylang.org/en/latest/types.html#function-types )
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
library ArrayUtils {
// internal functions can be used in internal library functions because
// they will be part of the same code context
function map(uint[] memory self, function (uint) pure returns (uint) f)
internal
pure
returns (uint[] memory r)
{
r = new uint[](self.length);
for (uint i = 0; i < self.length; i++) {
r[i] = f(self[i]);
}
}
function reduce(
uint[] memory self,
function (uint, uint) pure returns (uint) f
)
internal
pure
returns (uint r)
{
r = self[0];
for (uint i = 1; i < self.length; i++) {
r = f(r, self[i]);
}
}
// more methods...
}
Wie in anderen Antworten erwähnt, gibt es unterschiedliche Antworten auf Ihre Frage, je nachdem, ob Sie die Funktion "extern" oder "intern" aufrufen.
Innerhalb desselben Vertrags enthalten neuere Solidity-Versionen Sprachfunktionen, um einen "Funktionszeiger" herumzureichen (es ist nicht wirklich ein Zeiger an sich, aber er verhält sich wie einer). Mit anderen Worten, es gibt Variablen vom Typ "Funktion". Das ist, was ich meine, wenn ich eine Funktion "intern" umgebe und aufrufe.
Für „externe“ Aufrufe, dh Funktionsaufrufe an eine On-Chain-Adresse, würden Sie Solidity-Adresstypmember „call()“ und/oder Yul (Assembly) usw. verwenden, um einen Vertragsaufruf zu emulieren, da Solidity einen solchen Funktionsaufruf kompilieren würde wenn es als "someAddr.someFunction()" ausgedrückt wird ... und dies läuft darauf hinaus, die Funktionssignatur als Selektor zu codieren (Selektoren sind die ersten 4 Bytes des Hashs der Funktionssignatur) plus die Argumente, die Sie übergeben möchten, und die auszuführen erforderlichen EVM-Bytecodes (Assembly) unter Verwendung dieser Daten.
Mit anderen Worten, für "externe" Funktionen ist der "Funktionszeiger" das Tupel (Adresse, Selektor).
Niksmac
Karl Flörsch
Niksmac
Karl Flörsch
dbryson
Niksmac
Nick Johnson