静态类型语言和动态类型语言有什么区别?

我听到很多新的编程语言是动态类型的,但是当我们说一种语言是动态类型的还是静态类型的时候,这实际上意味着什么呢?

如果在编译时知道变量的类型,则语言是静态类型的。 对于某些语言来说,这意味着你作为程序员必须指定每个变量的类型(例如:Java,C,C ++)。 其他语言提供某种形式的类型推断 ,类型系统能够推导变量的类型(例如:OCaml,Haskell,Scala,Kotlin)

这里的主要优点是编译器可以进行各种检查,因此很早就发现了很多微不足道的错误。

如果类型与运行时间值相关联,则语言是动态类型的,而不是命名变量/字段/等。 这意味着你作为一个程序员可以写得更快一些,因为你不必每次都指定类型(除非使用类型推理的静态类型语言)。 例如:Perl,Ruby,Python

大多数脚本语言都具有这个特性,因为没有编译器可以进行静态类型检查,但是你可能会发现自己正在寻找一个由于解释器错误地解释变量类型而导致的错误。 幸运的是,脚本通常很小,所以错误没有太多地方可以隐藏。

大多数动态类型语言允许您提供类型信息,但不需要它。 目前正在开发的一种语言Rascal采用了一种混合方法,允许在函数内动态键入,但是为函数签名实施静态类型。

静态类型编程语言在编译时进行类型检查(验证和强制执行类型约束的过程),而不是运行时。

动态类型编程语言在运行时进行类型检查,而不是编译时。

下面是一个对比Python (动态类型)和Go (静态类型)如何处理类型错误的例子:

 def silly(a): if a > 0: print 'Hi' else: print 5 + '3' 

Python在运行时进行类型检查,因此:

 silly(2) 

运行完美,并产生预期的输出Hi 。 错误仅在有问题的行被触发时引发:

 silly(-1) 

产生

 TypeError: unsupported operand type(s) for +: 'int' and 'str' 

因为相关的行被实际执行。

另一方面在编译时进行类型检查:

 package main import ("fmt" ) func silly(a int) { if (a > 0) { fmt.Println("Hi") } else { fmt.Println("3" + 5) } } func main() { silly(2) } 

以上不会编译,出现以下错误:

 invalid operation: "3" + 5 (mismatched types string and int) 

简单地说就是:在一个静态类型的语言中,变量的类型是静态的 ,意思是一旦你设置一个变量为一个类型,你就不能改变它。 这是因为键入与变量而不是它所指的值相关联。

例如在Java中:

 String str = "Hello"; //variable str statically typed as string str = 5; //would throw an error since str is supposed to be a string only 

另一方面:在一个动态类型的语言中,变量的类型是动态的 ,意思是在你设置一个变量为一个类型后,你可以改变它。 这是因为键入与它所取的值而不是变量本身相关联。

例如在Python中:

 str = "Hello" # variable str is linked to a string value str = 5 # now it is linked to an integer value; perfectly OK 

所以,最好把动态类型语言中的变量看作类型值的泛型指针

总而言之, 输入描述(或应该描述)语言中的变量而不是语言本身。 它可以被更好地用作静态类型变量 的语言与动态类型变量的语言 IMHO。

静态类型语言通常是编译语言,因此,编译器会检查类型(完全正确,因为类型不允许在运行时稍后进行更改)。

动态类型的语言通常被解释,因此类型检查(如果有的话)在运行时使用。 这当然会带来一些性能成本,并且是动态语言(例如,python,ruby,php)不能像打印类型(java,c#等)那样好的原因之一。 从另一个角度来看,静态类型语言有更多的启动成本:使您通常编写更多的代码,更难的代码。 但是,这后付款。

好事是双方都从对方那里借用功能。 类型化语言包含了更多的动态特性,例如,c#中的泛型和动态库,动态语言包括更多的类型检查,例如python中的类型注释或者PHP的HACK变体,这些变体通常不是语言的核心,需求。

在技​​术选择方面,双方都没有内在的优势。 这只是一个偏好问题,你是想要更多的控制开始还是灵活性。 只要选择适合的工具,并确保在考虑交换机之前检查相反的方面。

http://en.wikipedia.org/wiki/Type_system

静态打字

编程语言被认为是在编译时进行类型检查时使用静态类型检查,而不是运行时。 在静态类型中,类型与变量而不是值相关联。 静态类型语言包括Ada,C,C ++,C#,JADE,Java,Fortran,Haskell,ML,Pascal,Perl(关于区分标量,数组,哈希和子程序)和Scala。 静态输入是程序验证的有限形式(参见类型安全):因此,它允许在开发周期的早期捕获许多类型的错误。 静态类型检查器只评估可以在编译时确定的类型信息,但是能够验证检查的条件适用于程序的所有可能的执行,这消除了每次程序执行时重复类型检查的需要。 通过省略运行时类型检查并启用其他优化,程序执行也可以更高效(即更快或减少内存)。

因为它们在编译期间评估类型信息,并且因此缺少仅在运行时可用的类型信息,所以静态类型检查器是保守的。 他们会拒绝一些在运行时可能表现良好的程序,但是不能被静态地确定为良好的类型。 例如,即使表达式总是在运行时计算为真,一个包含代码的程序也是如此

 if <complex test> then 42 else <type error> 

将被拒绝为不良类型的,因为静态分析不能确定else分支将不会被采取[1]。 静态类型检查器的保守行为在评估为不经常出现时很有利:静态类型检查器可以在很少使用的代码路径中检测类型错误。 没有静态类型检查,即使是覆盖率为100%的代码覆盖率测试,也可能无法找到这种类型的错误。 代码覆盖率测试可能无法检测到这种类型的错误,因为必须考虑创建值的所有地方和使用特定值的所有地方的组合。

使用最广泛的静态类型语言不是正式类型安全的。 他们在编程语言规范中有“漏洞”,使编程人员能够编写代码来绕过由静态类型检查器执行的验证,从而解决更广泛的问题。 例如,Java和大多数C风格的语言都有类型双关,而Haskell具有unsafePerformIO这样的特性:这样的操作在运行时可能是不安全的,因为在程序运行时,由于输入的值不正确,会导致不希望的行为。

动态类型

一种编程语言被认为是动态类型的,或者只是“动态的”,当它的大部分类型检查是在运行时而不是在编译时执行的。 在动态类型中,类型与值而不是变量相关联。 动态类型语言包括Groovy,JavaScript,Lisp,Lua,Objective-C,Perl(与用户定义的类型相关但不包含内置类型),PHP,Prolog,Python,Ruby,Smalltalk和Tcl。 与静态类型相比,动态类型可以更加灵活(例如,通过允许程序基于运行时数据生成类型和功能),尽管以较少的先验保证为代价。 这是因为动态类型语言接受并试图执行一些可能被静态类型检查器判定为无效的程序。

动态类型可能会导致运行时类型错误 – 也就是说,在运行时,一个值可能会有一个意外的类型,并且会应用一个对该类型无意义的操作。 这个操作可能发生在编程错误发生的地方之后很长时间,也就是说,错误类型的数据传递到一个不应该有的地方。 这使得难以定位的bug。

动态类型的语言系统与静态类型的表兄弟相比,对源代码进行的“编译时间”检查更少(但会检查程序在语法上是否正确)。 运行时检查可能会更复杂,因为它们可以使用动态信息以及编译期间出现的任何信息。 另一方面,运行时检查只声明条件在程序的特定执行中保持,并且对于程序的每次执行都重复这些检查。

动态类型语言的开发经常受编程实践的支持,如单元测试。 测试是专业软件开发的一个关键实践,在动态类型语言中尤为重要。 在实践中,为了确保正确的程序操作而进行的测试可以检测比静态类型检查更广泛的错误,但是相反,不能全面地搜索测试和静态类型检查能够检测到的错误。 测试可以包含到软件构建周期中,在这种情况下,可以将其视为“编译时”检查,因为程序用户不必手动运行这些测试。

参考

  1. 皮尔斯,本杰明(2002)。 类型和编程语言。 MIT出版社。 ISBN 0-262-16209-1。

不幸的是,“动态输入”这个术语是令人误解的。 所有的语言都是静态类型的,类型是表达式的属性(不像某些人认为的那样)。 但是,一些语言只有一种类型。 这些被称为单类型语言。 这种语言的一个例子是无类型的lambda演算。

在无类型的lambda演算中,所有的项都是lambda项,并且对一个术语可以执行的唯一操作是将其应用于另一个术语。 因此,所有操作总是导致无限递归或lambda项,但从不发出错误信号。

然而,如果我们用原始数字和算术运算来扩充无类型的lambda积分,那么我们可以执行无意义的操作,例如把两个lambda项加在一起: (λx.x) + (λy.y) 。 人们可以争辩说,唯一可行的做法是在发生这种情况时发出错误信号,但为了能够做到这一点,每个值必须用一个指示符来标记,该指示符指示该术语是拉姆达项还是数字。 加法运算符然后将检查确实两个参数都被标记为数字,如果它们不是,则表示错误。 请注意,这些标签不是类型,因为类型是程序的属性,而不是这些程序产生的值。

一种单一类型的语言被称为动态类型。

诸如JavaScript,Python和Ruby之类的语言都是单一类型的。 同样,JavaScript中的typeof运算符和Python中的type函数也有误导性的名称; 他们返回与操作数关联的标签,而不是他们的类型。 同样,C ++中的dynamic_cast和Java中的instanceof 不会进行类型检查。

在编译时静态类型语言类型检查,类型不能改变。 (不要使用类型转换注释来创建一个新的变量/引用)。

动态类型的语言在运行时进行类型检查,并且可以在运行时更改变量的类型。

  • 在静态类型的语言中,变量与编译时已知的类型相关联,并且该类型在整个程序执行过程中保持不变。 等同地,该变量只能被赋值为已知/指定类型的一个实例。
  • 在动态类型语言中,变量没有类型,在执行时它的值可以是任何形状和形式的任何类型。

简单的定义,但符合需求:静态类型语言将类型绑定到整个范围的变量(Seg:SCALA)。动态类型语言将类型绑定到由变量引用的实际值。

静态类型语言 :每个变量和表达式在编译时已经是已知的。

(int a; a在运行时只能取整数类型的值)

例如:C,C ++,JAVA

动态类型语言 :varialbes可以在运行时接收不同的值,并且在运行时定义类型。

(var a; a可以在运行时采取任何类型的值)

例如:Ruby,Python。

静态类型语言中 ,每个变量名都被绑定到一个类型(在编译时,通过数据声明)。 绑定到一个对象是可选的 – 如果一个名字没有绑定到一个对象,那么这个名字就是空的。 在动态类型语言中 ,每个变量名都是(除非是空的)只能绑定到一个对象。

名字通过赋值语句在执行时绑定到对象上,并且可以在执行程序的过程中将名字绑定到不同类型的对象上。

静态类型: Java和Scala等语言是静态类型的。

变量必须在代码中使用之前进行定义和初始化。

例如。 int x; x = 10;

的System.out.println(X);

动态输入: Perl是一种动态输入语言。

变量在用于代码之前不需要初始化。

Y = 10; 在代码后面的部分使用这个变量

Interesting Posts