Julia中的符号(Symbols )与Lisp、Scheme或Ruby中的符号相同。然而,在我看来,这些相关问题的答案并不令人满意。如果你读了这些答案,似乎符号与字符串的区别仅是,字符串是可变的,而符号是不变的,而且符号也是临时的。字符串在Ruby和Lisp中确实是可变的,但它们在Julia中是可变的,而且可变性实际上也是一种危险。事实上在Julia中符号是被内联的——即由语言实现进行哈希运算以便进行快速的比较(也是一个不相关的实现细节)。你可使用符号编写代码,并且这和内联的语言的实现将完全相同。
首先 什么是符号(Symbols )?答案是(在Julia和Lisp中这一点是相同的)能够将自定义的语言代码表示为语言本身的数据结构。有些人称之为“同形性”(Wikipedia),但有些人并不认为单凭这一点就足以使一种语言具有同形性。术语其实并不重要,关键是,当一种语言使用符号可以表示它自己的代码时,它需要一种方法来表示诸如赋值、函数调用 、可以写成文本值的表达式 等等。它还需要一种方法来表示它自己的变量。例如,你需要一种方法以数据结构的方式来表示这个左边的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的计算结果取决于绑定到变量fo的对象(如果有,可以是赋值、函数调用 、可以写成文本值的表达式 等等),而“foo”的计算结果总是“foo”。如果你想在Julia中构造使用变量的表达式,那么你使用的就是符号,例如:
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”,它也不会起作用。也就是说sym 必须被赋值为一个 Symbols 时,才会起作用。
这是符号(Symbols)的本质:符号用于表示元编程中的变量。当然,一旦将符号作为数据类型,就很容易将它们用作其他用途,例如散列键。
至于为什么在DF中使用符号而不是字符串,这是因为在DF中,将列值绑定到用户提供的表达式中的变量是一种常见的模式。所以列名自然是符号,因为符号正是用来将变量表示为数据的。目前,您必须编写df[:foo]才能访问foo列,但将来,您可能可以使用df.foo访问。这也是有前提的,只有其名称与某个列的标识符相等时,才能用这种方便的语法访问。
October-- 发布了93 篇原创文章 · 获赞 74 · 访问量 5万+ 私信 关注