我正在学习C,而且我知道如何在Mathematica上编程。
在Mathematica上,我可以简单地通过编写声明变量:
a=9
a="b"
a=9.5
似乎Mathematica通过简单地阅读并在其上找到某种模式,自然理解这是什么类型的变量。 (Int,char,float)。我猜Python有相同的功能。
在C语言中,我必须先说出它是什么:
int num;
char ch;
float f;
num=9;
ch='b';
f=9.5;
我知道这延伸到其他语言。所以我的问题是:为什么编程语言需要这种变量声明?
关于该主题的参考文献将非常有用。
答案 0 :(得分:6)
Mathematica,Python和其他“动态类型”语言具有由值和类型组成的变量,而像C这样的“静态类型”语言具有仅由值组成的变量。这不仅意味着存储变量需要更少的内存,而且动态类型语言必须在运行时设置和检查变量类型以了解变量包含的值的类型,而使用静态类型语言的类型,以及操作的内容可以/需要在它上面执行,在编译时是已知的。因此,静态类型语言要快得多。
此外,现代静态类型语言(例如C#和C ++ 11)具有类型推断,这通常使得不必提及类型。在像Haskell这样的类型推断的一些非常先进的静态类型语言中,可以在不指定类型的情况下编写大型程序,从而提供静态类型语言的效率以及动态类型语言的简洁性和便利性。
答案 1 :(得分:3)
声明是将C编译为高效二进制文件所必需的。基本上,这是为什么C比Mathematica快得多的重要部分。
答案 2 :(得分:3)
与大多数其他答案似乎相比,这与类型无关,可以很容易地推断(更不用说效率)了。这完全是关于范围的明确语义。
在允许对语言结构进行非平凡嵌套的语言中,对变量所属的位置以及哪些标识符引用相同变量有明确的规则非常重要。为此,每个变量都需要一个明确的范围来定义它可见的位置。没有明确的声明变量(无论是否带有类型注释),这在一般情况下是不可能的。
考虑一个简单的函数(您可以使用其他形式的嵌套作用域构造类似的示例):
function f() {
i = 0
while (i < 10) {
doSomething()
i = i + 1
}
}
function g() {
i = 0
while (i < 20) {
f()
i = i + 1
}
}
会发生什么?要告诉您,您需要知道i
将绑定在哪里:在全局范围内还是在本地函数范围内?后者意味着两个函数中的变量是完全分离的,而前者将使它们共享 - 并且这个特定的示例永远循环(尽管全局范围可能是其他示例中的预期)。
将上述内容与
进行对比function f() {
var i = 0
while (i < 10) {
doSomething()
i = i + 1
}
}
function g() {
var i = 0
while (i < 20) {
f()
i = i + 1
}
}
VS
var i
function f() {
i = 0
while (i < 10) {
doSomething()
i = i + 1
}
}
function g() {
i = 0
while (i < 20) {
f()
i = i + 1
}
}
这使得不同的可能含义非常清晰。
一般来说,没有好的规则能够(1)猜测程序员的真正含义,(2)在程序扩展或重构下足够稳定。更大更复杂的程序变得越来越糟糕。
避免毛茸茸的歧义和令人惊讶的错误的唯一方法是要求变量的显式声明 - 这是所有合理语言所做的。 (这是语言设计101,已经有50年了,不幸的是,这并不妨碍新一代语言“设计师”一遍又一遍地重复同样的错误,特别是在所谓的脚本语言中。直到他们学习艰苦的教训并纠正错误,例如ES6中的JavaScript。)
答案 3 :(得分:2)
变量类型是编译器必须能够验证是否为变量分配了正确的值类型所必需的。潜在的需求因语言而异。
答案 4 :(得分:2)
这与类型没有任何关系。考虑JavaScript,它具有不带类型的变量声明:
var x = 8;
y = 8;
原因是JavaScript需要知道您是指旧名称还是创建新名称。上面的代码会使任何现有的x
保持不变,但会破坏周围范围内现有y
的旧内容。
有关更详细的示例,请参阅this answer。
答案 5 :(得分:1)
从根本上说,您正在比较两种类型的语言,即由高级虚拟机或解释器(python,Mathematica ...)解释的语言和其他正在编译为本机二进制文件的语言(C,C ++ ...)在物理机器上执行,很明显,如果你可以定义自己的虚拟机,这为你的语言提供了极大的灵活性,与一个非常有限的物理机器相比,你的语言是多么动态和强大,结构和基本指令集的数量非常有限等等。在... ....
虽然某些编译为虚拟机或解释的语言仍然需要声明类型(java,C#),但这只是为了提高性能,想象必须在运行时推断类型或必须使用对于每种可能类型的基类型,这将消耗相当多的资源,更不用说使用JIT(只是及时编译器)很难实现本地运行的一些东西。