Julia中的符号与Lisp,Scheme或Ruby中的符号相同。但是,我认为这些相关问题的答案并不十分令人满意。如果您阅读了这些答案,似乎符号与字符串不同的原因是字符串是可变的,而符号是不可变的,符号也被“ interned”(无论如何)。字符串在Ruby和Lisp中确实是可变的,但在Julia中却不是,并且实际上是红鲱鱼。插入符号的事实(即,由语言实现进行哈希处理以进行快速相等比较)也是一个不相关的实现细节。您可能会实现一个不使用符号的实现,并且语言将完全相同。
那么,什么是符号呢?答案在于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
求值取决于变量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
。如果有可能,则使用此方便的语法只能访问名称为有效标识符的列。
也可以看看: