动态语言允许使用仅在运行时才知道的变量的值进行分派(dispatch)和调用。 Perl 中的对比示例:
类名
常量
Foo::Bar->some_method Foo::Bar::->some_method 'Foo::Bar'->some_method
这些都是相同的,除了第一个是边缘情况。如果在范围内定义了一个具有该名称的子例程,则分派(dispatch)会在其返回值上发生,这会导致难以理解的错误。引用的版本始终是安全的。
动态
my $class_name = 'Foo::Bar'; $class_name->some_method
方法名
常量
Some::Class->foo_bar
动态
my $method_name = 'foo_bar'; Some::Class->$method_name
函数名
常量
foo_bar; (\&foo_bar)->()
动态
my $function_name = 'foo_bar'; (\&$function_name)->()
我想知道,变量名没有符号(通常或根本没有)的语言是如何处理这些问题的,特别是它们的语言设计者是如何消除以下歧义的?
- 解析类名
FooBar.some_method
其中类FooBar
可能是名称文字或值为类名的变量 - 调度到
SomeClass.foo_bar
,其中方法foo_bar
可能是名称文字或值为方法名称的变量 - 调用
foo_bar
,其中函数可能是名称文字或值为函数的变量
我主要对这个问题的标签中提到的三种语言感兴趣,但如果你知道另一种没有印记的动态语言,你也可以回答。
最佳答案
在 python 和 js 中(我的 ruby 有点生疏了)不可能在名称上下文中使用字符串。如果您尝试这样做,那将被解释为对字符串本身的操作:
class_name = 'Foo'
object = class_name()
> TypeError: 'str' object is not callable
应该首先通过在上下文/范围字典中查找来解析字符串:
class Foo:
....
object = globals()['Foo']()
或
function Foo() ....
object = new window['Foo'];
Python 提供全局和局部字典,js 只提供全局字典,所以除了无处不在的“eval”之外,没有办法从它的名称中获取局部值。
这同样适用于方法:您使用 getattr
(python) 或间接引用运算符 [...]
(js) 查找方法:
method_name = 'foo'
method = getattr(some_object, method_name)
method()
Javascript 代码稍微复杂一些,因为与 python 不同,返回的方法指针是未绑定(bind)的:
method_name = 'foo'
method = some_object[method_name].bind(some_object)
method()
如果没有 bind
,您将无法在方法中获得正确的 this
:
var obj = {
xyz: 42,
method: function() {
document.write(this.xyz)
}
}
var method_name = 'method';
var unbound_method = obj[method_name];
unbound_method() // prints undefined
var bound_method = obj[method_name].bind(obj);
bound_method() // prints 42
更正式地说,python/js中的点运算符.
(相当于php的::
和->
)需要一个右侧的标识符,并允许左侧的任意表达式。由于一切都是对象,如果左边的表达式返回一个字符串,则点适用于该字符串,而不适用于名称恰好等于该字符串的变量。
(附带说明,在点的右侧也允许表达式在技术上是可行的,这样 foo.('bar' + 'baz')
将解析为foo.barbaz
。我不知道支持这种语法的语言,但它看起来是 getattr
和类似方法的不错替代品)。
类似地,调用运算符 ()
允许在左侧使用复杂的表达式,此外,该表达式必须解析为“可调用”对象。因此,"someString"()
没有意义,因为字符串通常是不可调用的(除非您以某种方式破解它们,使它们可以调用)。
也就是说,如果你有一个包含变量名的字符串,你必须在使用前显式解析它。在幕后为您执行此操作的语言没有任何魔力。
关于javascript - 变量没有符号的语言如何处理动态调度/调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26402047/