Символы в Julia такие же, как в Lisp, Scheme или Ruby. Однако, на мой взгляд , ответы на эти вопросы не совсем удовлетворительны . Если вы читаете эти ответы, кажется, что причина, по которой символ отличается от строки, заключается в том, что строки являются изменяемыми, в то время как символы неизменны, и символы также «интернированы» - что бы это ни значило. Строки действительно могут быть изменяемыми в Ruby и Lisp, но их нет в Julia, и это различие на самом деле отвлекает. Тот факт, что символы интернированы, то есть хешируются реализацией языка для быстрого сравнения на равенство, также является несущественной деталью реализации. У вас может быть реализация, в которой не используются внутренние символы, и язык будет точно таким же.
Так что же такое символ на самом деле? Ответ кроется в том, что у Julia и Lisp общее - в способности представлять код языка как структуру данных на самом языке. Некоторые люди называют это «гомоиконностью» ( Википедия ), но другие, похоже, не думают, что одного этого достаточно для того, чтобы язык был гомоиконным. Но терминология особого значения не имеет. Дело в том, что когда язык может представлять свой собственный код, ему нужен способ представления таких вещей, как присваивания, вызовы функций, вещи, которые могут быть записаны как буквальные значения и т. Д. Ему также нужен способ представления собственных переменных. То есть вам нужен способ представить - как данные - foo
левую часть этого:
foo == "foo"
Теперь мы подходим к сути вопроса: разница между символом и строкой - это разница между foo
левой частью этого сравнения и "foo"
правой частью. Слева foo
- идентификатор, который оценивает значение, привязанное к переменной foo
в текущей области. Справа "foo"
- строковый литерал, оценивающий строковое значение «foo». Символ как в Lisp, так и в Julia - это то, как вы представляете переменную как данные. Строка просто представляет себя. Вы можете увидеть разницу, применив eval
к ним:
julia> eval(:foo)
ERROR: foo not defined
julia> foo = "hello"
"hello"
julia> eval(:foo)
"hello"
julia> eval("foo")
"foo"
То, что символ :foo
оценивает, зависит от того, к чему - если вообще что-либо - переменная foo
привязана, тогда как "foo"
всегда просто оценивается как "foo". Если вы хотите создавать выражения в Julia, которые используют переменные, вы используете символы (знаете вы об этом или нет). Например:
julia> ex = :(foo = "bar")
:(foo = "bar")
julia> dump(ex)
Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol foo
2: String "bar"
typ: Any
То, что вываливали, показывает, среди прочего, что есть :foo
объект символа внутри объекта выражения, который вы получаете, цитируя код foo = "bar"
. Вот еще один пример построения выражения с символом, :foo
хранящимся в переменной 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"
Если вы попытаетесь сделать это, когда sym
привязан к строке "foo"
, это не сработает:
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""
Понятно, почему это не сработает - если вы попытались назначить "foo" = "bar"
вручную, это тоже не сработает.
В этом суть символа: символ используется для представления переменной в метапрограммировании. Если у вас есть символы в качестве типа данных, конечно, возникает соблазн использовать их для других вещей, например, в качестве хеш-ключей. Но это случайное, оппортунистическое использование типа данных, имеющего другую основную цель.
Обратите внимание, что я перестал говорить о Ruby некоторое время назад. Это потому, что Ruby не гомоиконичен: Ruby не представляет свои выражения как объекты Ruby. Итак, тип символа Ruby - это своего рода рудиментарный орган - оставшаяся адаптация, унаследованная от Lisp, но больше не используемая по своему первоначальному назначению. Символы Ruby были использованы для других целей - в качестве ключей хеширования для извлечения методов из таблиц методов - но символы в Ruby не используются для представления переменных.
Что касается того, почему символы используются в DataFrames, а не в строках, это потому, что это распространенный шаблон в DataFrames для привязки значений столбцов к переменным внутри предоставленных пользователем выражений. Поэтому естественно, чтобы имена столбцов были символами, поскольку символы - это именно то, что вы используете для представления переменных в виде данных. В настоящее время df[:foo]
для доступа к foo
столбцу необходимо писать , но в будущем вы можете получить к нему доступ как df.foo
вместо этого. Когда это станет возможным, с этим удобным синтаксисом будут доступны только столбцы, имена которых являются допустимыми идентификаторами.
Смотрите также: