我对静态类型语言没有太多经验(目前正在学习Scala并喜欢它!)但我注意到的一件事是它们似乎没有像Ruby的method_missing或ColdFusion的onMissingMethod那样的东西。静态类型语言是否存在一些固有的限制,可以防止或使其变得困难?
答案 0 :(得分:21)
当然可以添加一种处理它们的机制,但它与静态类型的不一致:编译时确定您的程序没有类型错误。
<强>附录强>
Scala 2.9引入了一个实验选项,可以通过这种方式动态处理对类型的访问,否则会导致静态类型检查失败。虽然它仍然由默认禁用功能标志控制,但它在2.10中被改进并变为非实验性的。您可以在SIP 17文档中阅读相关内容。有关Scala 2.10的“模块化”和功能标记的解释,请参阅SIP 18。
答案 1 :(得分:2)
Scala版本2.9通过Dynamic
特征(scaladoc)引入了此功能。扩展Dynamic
的类获得了神奇的方法applyDynamic(methodName, args)
,类似于Ruby的method_missing
。从Scala 2.9开始,必须启用-Xexperimental
选项才能使用Dynamic
。
答案 2 :(得分:1)
在静态类型语言中,直接调用成员函数。如果编译器无法确定要调用的成员函数,则程序将无法编译。从这个意义上讲,方法调用是静态的。
在动态类型语言中,不直接调用成员函数。相反,调用代码会向对象发送消息,然后语言运行时会确定如何处理该消息。例如,运行时将扫描对象以查找具有相同名称的方法,然后将扫描对象以查找名为method_missing
的方法。从这个意义上讲,方法调用是动态的。
C#4将静态类型与动态类型相结合。变量的编译时类型可能为dynamic
。对此变量的任何方法调用都将按照动态类型语言进行处理。对静态类型变量的任何方法调用都将按静态类型语言进行处理。
# static invocation, bound at compile time by the compiler
var s = 6;
s.ToString();
# dynamic invocation, handled at runtime by the CLR
dynamic d = 6;
d.ToString();
答案 3 :(得分:1)
仅仅为了进一步发展Randall的帖子,这是有可能的,但它违背静态范式的原因是它超出了“动态调度”。动态调度可以让您调度到动态绑定到已知静态代码段的函数。即,编译器从其角度设置在运行时确定性执行的调度。
method_missing
调用的作用,本质上是一个“全部捕获”,你根据方法名称决定做什么,使用switch语句或等效的东西(我相信你知道)。因此,编译器不知道这里会发生什么。假设编译器做了类似的事情:
if (function is known at compile time)
{
provide static call or dynamic call to "some" derivation
}
else
{
bind the function call to obj.method_missing(...) and pass in the "details"
}
然后你必须像这样提供method_missing
:
def method_missing(intendedFunctionName, arguments)
{
if (intendedFunctionName is "X")
{
X may not need arguments, so just do something
}
else if (intendedFunctionName is "Y")
{
Y expects 5 arguments of varying types
Throw exception if there isn't the right number or types
}
... etc ...
}
要求编译器向您发送“任意”(即在编译时不知道)任意类型的参数,使用intendedFunctionName
,您可能不会考虑......好吧,它不是很安全,并且Scala旨在成为一种静态安全的语言。
是的,它是可行的,但不是静态语言的精神。如果你真的想要那种灵活性,多语言编程可能是你的朋友。
注意:Objective-C不是严格静态类型的。有一个运行时引擎,代码在其上执行,动态类型系统不允许像C / C ++一样剥离或内联代码。
答案 4 :(得分:0)
Objective-C有“method_missing”(具体来说,forwardInvocation和methodSignatureForSelector),可以说是静态类型。这样做是因为它会在编译时将静态类型错误视为警告而不是错误,因为方法调度在运行时发生的程度远远大于C ++中的虚拟方法(这就是为什么你可以使用“method_missing”)。 / p>