Символы в 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вместо этого. Когда это станет возможным, с этим удобным синтаксисом будут доступны только столбцы, имена которых являются допустимыми идентификаторами.
Смотрите также: