Schreiben Sie eine Funktion (kein vollständiges Programm), sodass beim Aufruf der Funktion mit einer einzelnen globalen Variablen (oder dem nächstgelegenen Äquivalent Ihrer Sprache) als Argument der Name dieser Variablen ausgegeben (dh gedruckt oder zurückgegeben) wird. Wenn das Argument keine Variable ist, geben Sie stattdessen einen Falsey-Wert aus. (Sie müssen nicht den Fall behandeln, in dem das Argument eine Variable ist, aber nicht global.)
Zwischen dem Funktionsaufruf und der Funktionsdefinition darf während der Kompilierung keine Verbindung bestehen (insbesondere darf die Funktionsdefinition kein Makro oder ähnliches Konstrukt sein, das Argumente in Form eines wörtlichen Quellcodefragments empfängt, weder in Text noch in Form eines abstrakten Syntaxbaums bilden). Das heißt: In Sprachen, die eine separate Kompilierung unterstützen, muss das Programm auch dann funktionieren, wenn der Funktionsaufruf zuerst kompiliert wird (ohne Kenntnis der Funktionsdefinition, aber möglicherweise einer Typensignatur oder einer Entsprechung). Anschließend wird die Funktionsdefinition kompiliert. Wenn die Sprache keine separate Zusammenstellung hat, müssen Sie dennoch eine ähnliche Trennung zwischen Aufruf und Definition anstreben.
Wenn Sie eine kompilierte Sprache verwenden, können Sie die kompilierte Form des vollständigen Programms von der Festplatte lesen und davon ausgehen, dass das Programm mit Debug-Informationen kompiliert wurde. (Daher sind Lösungen zulässig, bei denen ein Debugger aus einem Programm an sich selbst angehängt wird.)
Beachten Sie, dass diese Aufgabe möglicherweise nicht in jeder Sprache möglich ist.
Beispiele:
var apple = "Hello"
p(apple) // apple
var nil = "Nothing"
p(nil) // nil
var SOMETHING = 69
p(SOMETHING) // SOMETHING
function foo(){}
p(foo) // foo
p(3.14159) // false
p(function foo(){}) // false
quelle
Antworten:
Java
Dies funktioniert derzeit mit ein paar Fallstricken:
javac
mit dem-g
Flag kompilieren . Dadurch werden alle Debugging-Informationen einschließlich der lokalen Variablennamen in der kompilierten Klassendatei generiert.com.sun.tools.javap
die den Bytecode einer Klassendatei analysiert und ein für den Menschen lesbares Ergebnis liefert. Auf diese API kann nur in den JDK-Bibliotheken zugegriffen werden. Sie müssen daher entweder die JDK-Java-Laufzeit verwenden oder tools.jar zu Ihrem Klassenpfad hinzufügen.Dies sollte nun auch dann funktionieren, wenn die Methode im Programm mehrfach aufgerufen wird. Leider funktioniert es noch nicht, wenn Sie mehrere Aufrufe in einer einzigen Zeile haben. (Für eine, die das tut, siehe unten)
Probieren Sie es online!
Erläuterung
In diesem ersten Teil erhalten Sie allgemeine Informationen darüber, in welcher Klasse wir uns befinden und wie die Funktion heißt. Dies wird erreicht, indem eine Ausnahme erstellt und die ersten 2 Einträge des Stack-Trace analysiert werden.
Der erste Eintrag ist die Zeile, in der die Ausnahme ausgelöst wird, von der wir den Methodennamen abrufen können, und der zweite Eintrag ist die Zeile, von der aus die Funktion aufgerufen wurde.
In dieser Zeile führen wir die im JDK enthaltene ausführbare Java-Datei aus. Dieses Programm analysiert die Klassendatei (Bytecode) und zeigt ein für Menschen lesbares Ergebnis an. Wir werden dies zum rudimentären "Parsen" verwenden.
Wir machen hier ein paar verschiedene Dinge. Zunächst lesen wir die Ausgabe von javap zeilenweise in eine Liste ein. Zweitens erstellen wir eine Zuordnung von Bytecode-Zeilenindizes zu Java-Zeilenindizes. Dies hilft uns später zu bestimmen, welchen Methodenaufruf wir analysieren möchten. Schließlich verwenden wir die bekannte Zeilennummer aus dem Stack-Trace, um zu bestimmen, welchen Bytecode-Zeilenindex wir betrachten möchten.
Hier iterieren wir noch einmal über die Java-Zeilen, um die Stelle zu finden, an der unsere Methode aufgerufen wird und an der die lokale Variablentabelle beginnt. Wir benötigen die Zeile, in der die Methode aufgerufen wird, da die Zeile vor ihr den Aufruf zum Laden der Variablen enthält und angibt, welche Variable (nach Index) geladen werden soll. Mithilfe der lokalen Variablentabelle können wir den Namen der Variablen anhand des von uns erfassten Index nachschlagen.
Dieser Teil analysiert tatsächlich den Ladeaufruf, um den Variablenindex zu erhalten. Dies kann eine Ausnahme auslösen, wenn die Funktion nicht tatsächlich mit einer Variablen aufgerufen wird, sodass hier null zurückgegeben werden kann.
Schließlich analysieren wir den Namen der Variablen aus der Zeile in der lokalen Variablentabelle. Gibt null zurück, wenn es nicht gefunden wird, obwohl ich keinen Grund gesehen habe, warum dies passieren sollte.
Alles zusammen
Dies ist im Grunde, was wir suchen. Im Beispielcode lautet der erste Aufruf Zeile 17. Zeile 17 in der LineNumberTable zeigt, dass der Anfang dieser Zeile der Bytecode-Zeilenindex 18 ist. Das ist die
System.out
Last. Dann müssen wiraload_2
direkt vor dem Methodenaufruf nach der Variablen in Slot 2 der LocalVariableTable suchen, wasstr
in diesem Fall der Fall ist.Hier ist zum Spaß einer, der mehrere Funktionsaufrufe auf derselben Leitung verarbeitet. Dies führt dazu, dass die Funktion nicht idempotent ist, aber genau darum geht es. Probieren Sie es online!
quelle
System.out.println(e.getParamName(str));System.out.println(e.getParamName(str2));System.out.println(e.getParamName(str4));
auf zu verschieben eine Zeile im TIO-Link.javap
Lage wie folgt aus :Paths.get(System.getProperty("java.home"), "bin", "javap")
.Python 2
Dies ist der schmutzigste Code, den ich geschrieben habe, aber er funktioniert. ¯ \ _ (ツ) _ / ¯ Wirft einen Fehler auf eine nicht existierende Variable, da Python Sie sofort nicht mag, wenn Sie die Funktion mit einer aufrufen. Wirft auch einen Fehler auf Nicht-Variablen, aber dies kann mit einem Versuch / außer bei Bedarf behoben werden.
Probieren Sie es online!
Wenn wir das Argument als Zeichenfolge verwenden dürfen, erfüllt dies die Anforderungen für die Ausgabe eines falschen Werts für eine ungültige Eingabe.
Probieren Sie es online!
quelle
Mathematica
Das
HoldFirst
Attribut verhindert, dassf
sein Argument ausgewertet wird, bevor die Funktion aufgerufen wird.ValueQ @ x
prüft dann, ob das angegebene Argument eine Variable ist, der ein Wert zugewiesen wurde. Wenn nicht, kehren wir nurFalse
wegen eines Kurzschlusses zurück. Ansonsten erhalten wir den Variablennamen mitToString @ HoldForm @ x
.quelle
And
ich missbrauche, wie Mathematica damit umgeht ... Ich mag, dass das richtige Argument vonAnd
nicht einmal ein boolescher Ausdruck sein muss.f[x_] := ValueQ @ x && HoldForm @ x
? Wenn es nicht erforderlich wäre, zu überprüfen, ob die Eingabe eine Variable ist,HoldForm
würde dies alleine funktionieren.HoldAll
stattHoldFirst
?HoldForm[a]
und nicht"a"
. Während sie im Mathematica-Notizbuch gleich angezeigt werden, gibt es die Funktion unabhängig vom Frontend. Daher wollte ich eine Lösung, die einen String zurückgibt.Mathematica
Mathematica bewertet gerne alles . Um aufzuhören, müssen wir dagegen ankämpfen. In seiner eigenen Sprache.
Wie?
Sagt Mathematica, dass beim
f
Aufruf einer Funktion deren Argumente nicht ausgewertet (dh festgehalten) werden sollen.Wenn
f
mit einem Argument aufgerufen wird, wird ausgegebenFalse
. (?!)Wenn
f
mit einem definierten Symbol (das einen Wert hat) aufgerufen wird, geben Sie den Symbolnamen der Eingabe aus.Die vorherige Zeile hat keinen Vorrang, obwohl sie zuvor definiert wurde, da diese Definition spezifischer ist. In der Wolfram-Dokumentation heißt es: Mathematica "versucht, bestimmte Definitionen vor allgemeinere zu setzen."
Mathematica ist sehr eigensinnig und versucht nach Möglichkeit, Variablen auszuwerten. Dafür
Unevaluated
sorgt das Extra .quelle
C #
Voll / Formatierte Version:
Eine andere Möglichkeit, dies zu tun, besteht darin, den Typ wie folgt zu reflektieren:
Sie müssen es jedoch so nennen:
Es schlägt dann auch fehl,
3.14159
indem Sie zurückkehren,Length
und dafür müssen Sie es stattdessen auch wie folgt aufrufen:In C # 6.0 haben wir auch:
Dies wird jedoch nicht kompiliert, wenn Sie etwas übergeben, das keine Variable ist, z
3.14159
. Ich glaube, es wertet auch die Eingabe zur Kompilierungszeit aus, so dass es den Anschein hat, als ob diese Anforderung ebenfalls nicht erfüllt wird.quelle
Expression
). Sie sollten auch zählenusing System.Linq.Expressions;
.MATLAB
Innerhalb einer Funktion gibt es einige voreingestellte Variablen wie
varargin
odernargin
, unter denen wir auch habeninputname
.von hier gestohlen
quelle
x=42;y=54; f=@(x)eval(inputname(1));f(x),f(y)
eval==evil
= D (es funktioniert tatsächlich mitx=42;y=54; f=@(x)eval('inputname(1)');f(x),f(y)
)x
kann und danneval
das Funktionsargument ist, nicht die Arbeitsbereichsvariable.R
substitute
Gibt den Analysebaum für einen nicht bewerteten Ausdruck zurück. Dieidentical
Bedingung stellt sicher, dass dieser nicht bewertete Ausdruck nicht mit dem Ausdruck selbst identisch ist. dh dass der übergebene Parameter kein Literal ist.quelle
Python 2
Einige Untersuchungen wurden durchgeführt. Und es scheint in Python möglich zu sein, aber ich erwarte immer noch, dass einige Probleme gefunden werden.
Die Lösung ist nicht perfekt, da sie eine gewisse Struktur des Codes annimmt. Trotzdem habe ich es nicht noch gebrochen.
Dies verwendet inspect, um das Surround-Oszilloskop zu untersuchen und festzustellen, wo die Funktion
get_name
aufgerufen wird. Zum Beispielinspect...[1]
wird zurückkehrenUnd
inspect...[1][4]
zeigt uns eine Liste mit Code, in der die Funktion aufgerufen wird:Danach habe ich Regex verwendet, um den Namen des Arguments abzurufen
Und
.lstrip().rstrip()
um alle Leerzeichen zu entfernen, die in Klammern gesetzt werden können.Beispiel mit einigen kniffligen Eingaben
quelle
Power Shell
Aber es funktioniert nicht zuverlässig, es ist rudimentär.
quelle
PHP
Erfordert, dass der Variablenwert im Array der globalen Variablen eindeutig ist
Probieren Sie es online!
PHP , 96 Bytes
Probieren Sie es online!
Benötigt, dass die Variable direkt auf den Funktionsaufruf initialisiert wird.
Überprüft, ob die letzte globale Variable gleich der übergebenden Variable ist
quelle
JavaScript (ES6)
Versuchen Sie, für alle Eigenschaftsnamen in
window
(Object.getOwnPropertyNames(w)
) einen Getter für diese Eigenschaft zu definieren, der den Eigenschaftsnamen zurückgibt.Fügen Sie dann einer Map einen Eintrag hinzu,
M
bei dem der Schlüssel der (möglicherweise überschriebene) Wert der Eigenschaft und der Wert der Name der Eigenschaft ist.Die Funktion
f
nimmt einfach eine Variable (dh eine Eigenschaft vonwindow
) und gibt den EintragM
für diesen Wert zurück.Dies funktioniert für alle eingebauten globalen Variablen außer für sich
window
selbst, da es keinen Unterschied gibttop
(es sei denn, sie werden in einem Frame ausgeführt):quelle
L not a function
. Warum sollte das passieren?Perl 5 + Devel :: Caller
Wir verwenden Devel :: Caller (ein Debugger-ähnliches Modul), um den Aufruf-Stack zu durchsuchen, nach dem Aufruf der Funktion zu suchen und alle Operanden innerhalb des Arguments als Variablennamen zurückzugeben. Wenn es mehr (oder weniger) als einen Operanden gibt, wurden wir nicht mit einer Variablen aufgerufen. Wenn der Operand keine Variable wäre, hätte er keinen Namen, und das können wir auch feststellen.
Der schwierigste Fall ist, wenn wir einen Ein-Operanden-Ausdruck mit einer Variablen erhalten, wie z
~$x
. Wir können herausfinden, ob dies aufgetreten ist, indem wir einen Verweis auf die Variable direkt aus der Symboltabelle (unter Verwendung der${…}
symbolischen Referenzsyntax) nehmen und ihre Speicheradresse mit dem Wert vergleichen, den wir als Argument übergeben haben (was günstigerweise als Verweis übergeben wird) ). Wenn sie unterschiedlich sind, haben wir eher einen Ausdruck als eine einzelne Variable.Beachten Sie, dass wir, wenn wir diese Funktion mit einem Vorinkrementierungs- oder Vordekrementierungsausdruck für eine einzelne Variable wie in aufrufen
v(--$x)
,$x
zurückgegeben werden. Dies liegt daran, dass in diesem Fall tatsächlich die Variable selbst an die Funktion übergeben wird. es wird nur vorher inkrementiert oder dekrementiert. Ich hoffe das disqualifiziert die Antwort nicht. (In gewisser Weise macht es es besser, weil es zeigt, dass wir das Argument selbst überprüfen, anstatt nur den Quellcode zu lesen.)quelle
PHP
Während die anderen PHP-Übermittlungen nur testen, ob der angegebene Wert mit einem Wert eines globalen übereinstimmt, funktioniert diese Version, indem sie auf den Wert verweist:
Dies sollte jetzt auch dann funktionieren, wenn die globale Variable zum Zeitpunkt des Aufrufs eine Referenz auf einen anderen Wert ist.
Teste es hier .
quelle
Röda
Probieren Sie es online!
Röda hat dafür eine eingebaute Funktion -
name
. Leider wird kein falscher Wert zurückgegeben, wenn keine Variable angegeben wird.Dieser Code missbraucht mehrere Funktionen der Referenzsemantik. Erklärung Zeile für Zeile:
f(&a...) {
Die Funktion akzeptiert eine variable Anzahl von Referenzargumenten (
&a...
). Nur so kann in Röda eine Referenzliste erstellt werden.a() | name(_) | for str do
In der zweiten Zeile werden die Elemente von
a
in den Stream (a()
) verschoben . Diese Elemente sind Referenzen, wenn der Funktion Variablen und ansonsten Normalwerte gegeben wurden.Die Elemente werden mit einer Unterstreichungsschleife iteriert. Die Unterstreichungssyntax ist Syntaxzucker für
for
Schleifen,name(_)
entspricht alsoname(var) for var
. Der Name der in derfor
Schleife verwendeten Variablen hat die Form,<sfvN>
in der N variiert. (Dh. "name(<sfv1>) for <sfv1>
") Es ist nicht zulässig, dass eine benutzerdefinierte Variable<
oder enthält>
, damit die generierten Namen nicht mit vorhandenen Variablennamen kollidieren.Die
name()
Funktion gibt den Namen der angegebenen Variablen zurück. Wenn es sich bei dem Elementa
, das iteriert wird, um eine Referenz handelt, handelt es sich um die Variable, die an übergeben wirdname
. Wenn das Element ein normaler Wert war, ist die angegebene Variablename
die Unterstrichvariable<sfvN>
. Dies liegt an der Semantik von Referenzen in Röda: Wenn eine Funktion eine Referenz akzeptiert und der Funktion eine Referenzvariable übergeben wird, zeigt der übergebene Wert nicht auf die Referenzvariable, sondern auf die Variable, auf die die Referenzvariable verweist.false if [ "<" in str ] else [str]
In der dritten Zeile prüfen wir, ob der Variablenname im Stream ein
<
Zeichen enthält . In diesem Fall handelt es sich um eine Unterstrichvariable, und der übergebene Wertf
war keine Referenz. Ansonsten geben wir den Namen der Referenz aus.Diese Lösung funktioniert nicht, wenn die der Funktion zugewiesene Variable eine Referenz- oder Unterstrichvariable ist. Die Frage gibt jedoch an, dass nur globale Variablen behandelt werden müssen und es sich in Röda nicht um Verweise oder Unterstreichungsvariablen handeln darf.
quelle
Ruby , 46 Bytes
Fühlt sich an wie der schmutzigste Code, den ich je für Ruby geschrieben habe.
Erfordert, dass die von Ihnen aufgerufenen globalen Variablen einen eindeutigen Wert haben, der sich auf keiner anderen globalen Variablen befindet, da die einzige Möglichkeit, diese Herausforderung in Ruby durchzuführen, darin besteht, alle globalen Variablen zu durchsuchen und die erste Übereinstimmung zurückzugeben. OP sagt, dass es in Ordnung ist und es steht mir frei zu beurteilen, ob meine Lösung gültig ist.
Beachten Sie, dass globale Variablen mit
$
Ruby beginnen, wenn Sie zusätzliche Testfälle hinzufügen möchten.Probieren Sie es online!
quelle
PHP
Wenn ein Wert gefunden wird, geben Sie den Variablennamen aus und beenden Sie das Programm. drucke nichts und beende sonst nicht.
61 Bytes zum Zurückgeben des Variablennamens oder
NULL
:Es werden keine benannten Funktionen gefunden, nur die, die Variablen zugewiesen sind.
Und eine PHP-Funktion kann nicht erkennen, ob ein Parameter als Referenz oder als Wert angegeben wurde. Die Funktion gibt nur den Vornamen zurück, bei dem der Wert mit dem Funktionsparameterwert übereinstimmt.
Testen Sie es online
quelle
Power Shell
Neue Version funktioniert aber ab PowerShell 3.0
Probieren Sie es online!
Vorherige Version
Probieren Sie es online!
quelle
tcl
Demo
quelle
JavaScript (ES6)
Erfordert, dass der Wert der an die Funktion übergebenen Variablen für diese Variable eindeutig ist. Gibt zurück,
undefined
wenn eine Variable nicht übergeben wurde.Versuch es
Aus irgendeinem Grund wird in einem Snippet ein ursprungsübergreifender Fehler ausgegeben, wenn ein "Literal" übergeben wird.
Erläuterung
Durchlaufen Sie alle Einträge im globalen Objekt (
this
) und überprüfen Sie, ob der Wert jedes einzelnen Objekts genau dem Wert des an die Funktion übergebenen Arguments entspricht. Wird ein passender Eintrag gefunden, wird dessen Schlüssel (Name) zurückgegeben und die Funktion verlassen.Alternative
Mit den gleichen Anforderungen wie oben
quelle
hello--
. B. ). Außerdem müssten Sievar
eher als verwendenlet
.let
undvar
. Zu Ihrer zweiten Frage: Das ist passiert, weil Sie eine Variable haben, dieIN_GLOBAL_SCOPE
in Ihrem globalen Gültigkeitsbereich benannt ist und einen Wert von hat1
. Sie können die vorhandenen Variablen in Ihrem globalen Bereich und ihre Werte überprüfen, indem Sie diesefor(x in this)console.log(x+": "+this[x])
Schnell, 45 Bytes
quelle
value of type 'Mirror' has no member 'label'