Символи у Джулії такі ж, як у Ліспа, Схеми або Рубі. Однак, на мою думку , відповіді на ці пов'язані питання не дуже задоволені . Якщо ви читаєте ці відповіді, то здається, що причина символу інша, ніж рядок, полягає в тому, що рядки є змінними, тоді як символи незмінні, а символи також "інтерновані" - що б це не означало. Струни в Рубі та Ліспі бувають непомітними, але їх немає у Джулії, і ця різниця насправді є червоною оселедець. Те, що символи інтерновані - тобто хешировані мовою впровадження для швидкого порівняння рівності - також є неактуальною деталлю реалізації. У вас може бути реалізація, яка не інтернує символи, і мова буде абсолютно однаковою.
Отже, що насправді є символом? Відповідь полягає у чомусь спільному Джулії та Лісп - здатності представляти код мови як структуру даних у самій мові. Деякі люди називають це "гомоніконічністю" ( Вікіпедія ), але інші, здається, не вважають, що однієї достатньо для того, щоб мова була гомоніконічною. Але термінологія насправді не має значення. Справа в тому, що коли мова може представляти власний код, їй потрібен спосіб представлення речей, таких як призначення, виклики функцій, речі, які можна записати як буквальні значення тощо. Також він потребує способу представлення власних змінних. Тобто вам потрібен спосіб представити - як дані - foo
ліворуч від цього:
foo == "foo"
Тепер ми переходимо до суті справи: різниця між символом та рядком - це різниця між foo
лівою частиною цього порівняння та "foo"
правою. Зліва foo
- це ідентифікатор, який оцінює значення, пов'язане зі змінною foo
в поточній області. Праворуч "foo"
- це літеральний рядок, який оцінює значення рядка "foo". Символом і Ліспа, і Джулії є те, як ви представляєте змінну як дані. Рядок просто представляє себе. Ви можете побачити різницю, застосувавши 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 не використовуються для представлення змінних.
Що стосується того, чому символи використовуються в DataFrames, а не рядки, це тому, що це звичайний зразок в DataFrames, щоб прив'язувати значення стовпців до змінних всередині наданих користувачем виразів. Тому природно, що назви стовпців мають бути символами, оскільки символи - це саме те, що ви використовуєте для представлення змінних як даних. Наразі вам доведеться писати, df[:foo]
щоб отримати доступ до foo
стовпця, але в майбутньому ви зможете отримати доступ до нього як df.foo
натомість. Коли це стане можливим, до цього зручного синтаксису будуть доступні лише стовпці, імена яких є дійсними ідентифікаторами.
Дивитися також: