Die Symbole in Julia sind dieselben wie in Lisp, Scheme oder Ruby. Die Antworten auf diese verwandten Fragen sind meiner Meinung nach jedoch nicht wirklich zufriedenstellend . Wenn Sie diese Antworten lesen, scheint der Grund, warum sich ein Symbol von einer Zeichenfolge unterscheidet, darin zu liegen, dass Zeichenfolgen veränderbar sind, während Symbole unveränderlich sind, und Symbole auch "interniert" werden - was auch immer das bedeutet. Saiten sind in Ruby und Lisp zwar veränderlich, aber in Julia nicht, und dieser Unterschied ist eigentlich ein roter Hering. Die Tatsache, dass Symbole interniert werden, dh von der Sprachimplementierung für schnelle Gleichheitsvergleiche gehasht werden, ist ebenfalls ein irrelevantes Implementierungsdetail. Sie könnten eine Implementierung haben, die keine Symbole interniert, und die Sprache wäre genau dieselbe.
Was ist eigentlich ein Symbol? Die Antwort liegt in etwas, das Julia und Lisp gemeinsam haben - der Fähigkeit, den Code der Sprache als Datenstruktur in der Sprache selbst darzustellen. Einige Leute nennen dies "Homoikonizität" ( Wikipedia ), andere scheinen nicht zu glauben, dass allein eine Sprache ausreicht, um homoikonisch zu sein. Aber die Terminologie spielt keine Rolle. Der Punkt ist, dass eine Sprache, wenn sie ihren eigenen Code darstellen kann, eine Möglichkeit benötigt, Dinge wie Zuweisungen, Funktionsaufrufe, Dinge, die als Literalwerte geschrieben werden können usw. darzustellen. Sie benötigt auch eine Möglichkeit, ihre eigenen Variablen darzustellen. Das heißt, Sie benötigen eine Möglichkeit, die Daten foo
auf der linken Seite als Daten darzustellen :
foo == "foo"
Jetzt kommen wir zum Kern der Sache: Der Unterschied zwischen einem Symbol und einer Zeichenfolge ist der Unterschied zwischen foo
auf der linken Seite dieses Vergleichs und "foo"
auf der rechten Seite. Auf der linken Seite foo
befindet sich ein Bezeichner, der den Wert auswertet, der foo
im aktuellen Bereich an die Variable gebunden ist . Auf der rechten Seite "foo"
befindet sich ein Zeichenfolgenliteral, das den Zeichenfolgenwert "foo" ergibt. Ein Symbol in Lisp und Julia ist, wie Sie eine Variable als Daten darstellen. Eine Zeichenfolge repräsentiert nur sich selbst. Sie können den Unterschied erkennen, indem Sie sich eval
bei ihnen bewerben :
julia> eval(:foo)
ERROR: foo not defined
julia> foo = "hello"
"hello"
julia> eval(:foo)
"hello"
julia> eval("foo")
"foo"
Was das Symbol :foo
ergibt, hängt davon ab, an was - wenn überhaupt - die Variable foo
gebunden ist, während es "foo"
immer nur "foo" ergibt . Wenn Sie in Julia Ausdrücke erstellen möchten, die Variablen verwenden, verwenden Sie Symbole (unabhängig davon, ob Sie sie kennen oder nicht). Beispielsweise:
julia> ex = :(foo = "bar")
:(foo = "bar")
julia> dump(ex)
Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol foo
2: String "bar"
typ: Any
Was das abgelegte Zeug zeigt, ist unter anderem, dass sich :foo
innerhalb des Ausdrucksobjekts ein Symbolobjekt befindet, das Sie durch Zitieren des Codes erhalten foo = "bar"
. Hier ist ein weiteres Beispiel für die Erstellung eines Ausdrucks mit dem :foo
in der Variablen gespeicherten Symbol sym
:
julia> sym = :foo
:foo
julia> eval(sym)
"hello"
julia> ex = :($sym = "bar"; 1 + 2)
:(begin
foo = "bar"
1 + 2
end)
julia> eval(ex)
3
julia> foo
"bar"
Wenn Sie dies versuchen, wenn sym
es an die Zeichenfolge gebunden ist, "foo"
funktioniert es nicht:
julia> sym = "foo"
"foo"
julia> ex = :($sym = "bar"; 1 + 2)
:(begin
"foo" = "bar"
1 + 2
end)
julia> eval(ex)
ERROR: syntax: invalid assignment location ""foo""
Es ist ziemlich klar, warum dies nicht funktioniert - wenn Sie versucht haben, "foo" = "bar"
von Hand zuzuweisen , funktioniert es auch nicht.
Dies ist die Essenz eines Symbols: Ein Symbol wird verwendet, um eine Variable in der Metaprogrammierung darzustellen. Sobald Sie Symbole als Datentyp haben, wird es natürlich verlockend, sie für andere Zwecke zu verwenden, beispielsweise als Hash-Schlüssel. Dies ist jedoch eine zufällige, opportunistische Verwendung eines Datentyps, der einen anderen Hauptzweck hat.
Beachten Sie, dass ich vor einiger Zeit aufgehört habe, über Ruby zu sprechen. Das liegt daran, dass Ruby nicht homoikonisch ist: Ruby repräsentiert seine Ausdrücke nicht als Ruby-Objekte. Rubys Symboltyp ist also eine Art Überrestorgan - eine übrig gebliebene Adaption, die von Lisp geerbt wurde, aber nicht mehr für den ursprünglichen Zweck verwendet wird. Ruby-Symbole wurden für andere Zwecke kooptiert - als Hash-Schlüssel, um Methoden aus Methodentabellen zu ziehen -, aber Symbole in Ruby werden nicht zur Darstellung von Variablen verwendet.
Der Grund, warum Symbole in DataFrames anstelle von Zeichenfolgen verwendet werden, liegt darin, dass in DataFrames häufig Muster verwendet werden, um Spaltenwerte an Variablen innerhalb von vom Benutzer bereitgestellten Ausdrücken zu binden. Daher sind Spaltennamen natürlich Symbole, da Symbole genau das sind, was Sie zur Darstellung von Variablen als Daten verwenden. Derzeit müssen Sie schreiben, df[:foo]
um auf die foo
Spalte zuzugreifen. In Zukunft können Sie jedoch möglicherweise stattdessen darauf zugreifen df.foo
. Wenn dies möglich wird, können mit dieser praktischen Syntax nur auf Spalten zugegriffen werden, deren Namen gültige Bezeichner sind.
Siehe auch: