动态语言和静态语言都可以是强类型的。主要的差别在于类型检查的时候。强类型的静态语言在编译的时候执行类型检查,而强类型的动态语言在运行的时候做类型检查。也许把他们称作动态检查语言和静态检查语言会更加清晰。此外还有2个和类型相关的不同点。改变变量类型和改变类型的定义。如下的例子:

下面的C#代码引起一个编译错误,因为C#和多数静态语言一样,不允许改变变量的类型。

//explicit static typing. Causes compilation error.

int i = 3;

i = “hello”;

下面的C#代码也引起编译错误,即使我们使用var关键字声明变量i。和之前变量不同在于,下面的代码,编译器自动为我们推断i的类型。

//implicit static typing. Causes compilation error.

var i = 3;

i = “hello”;

C#4.0中,有新的关键字dynamic,如果我们使用这关键字声明变量,就等于告诉C#编译器,变量类型可以改变。下面代码的例子说明了这点。变量i不再是不可变的单一类型了。换句话说,它的类型是动态的。C#编译器在编译的时候不会对该类型做类型检查。

//dynamic typing. No compilation error. No runtime error.

dynamic i = 3;

i = “hello”;

C#允许变量呈现不同的类型。在动态语言中,不仅变量可以呈现不同类型。语句诸如if和switch也可以有不同的类型。下面的Python例子展示了if语句返回一个数字和string。if语句在名为callif的function中。如果你在C#中这样写代码,会得到编译错误。因为C#语言要求你在每个分支中返回的都是相同的类型。

def callIf(n):

if n > 5:

return 5

else:

return "hello"

x = callIf(6)

print x

print type(x)

x = callIf(4)

print x

print type(x)

上述代码运行结果

5

Hello

另一个静态语言和动态语言的不同点就是在运行的时候改变类型定义。静态语言不允许这么做。而动态语言诸如Python和Ruby可以,比如加入新的方法到类型中。

动态调度

当某行代码是方法调用的时候,编译器需要知道哪个类的哪个方法被调用了。方法有可能被重载,这样,编译器还要工具传递的参数选择正确的方法。相似的,当某一行代码是一个操作,编译器需要知道该用哪个操作符,操作符也可能被不同的类型重载了。这些都被称作方法绑定或者方法调度。

静态语言中,绑定是在编译时做的,因为编译在运行之前,绑定也被称作前期绑定。

动态语言中,绑定实在运行的时候做的,因此称作延迟绑定,也叫动态调度。下面的C#代码为前期绑定的例子,在编译时,C#编译器知道变量的类型为string。当调用ToLower方法时,编译器知道是调用String类的ToLower方法。它会检查并确定String类有这样的方法。

String name = "Bob";

String lowercaseName = name.ToLower();

下面的IronPython代码则是延迟绑定的例子。基本上,C#编译器上例C#代码所做的事情,现在由IronPython runtime在运行时候做,

name = "Bob";

在Python代码中,你不需要提供类型信息,开发过程中也没有类型检查。但当你运行代码的时候, IronPython runtime会执行类型检查和方法绑定,就行C#编译器在编译的时候做的那样。