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

当我们说一种语言是动态类型还是静态类型时,这意味着什么?

576691 次浏览

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

静态类型

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

因为它们评估类型信息在编译过程中,因此缺乏类型信息仅在运行时可用,静态类型Checkers很保守他们会的拒绝一些可能是在运行时表现良好,但是不能静态地确定为好的类型。例如,即使一个表达式总是在运行时计算为true,a包含代码的程序

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

将被拒绝为类型错误,因为静态分析无法确定其他分支就不会了[1]保守行为的静态类型检查器是有利时不常计算为false:A静态类型检查器可以检测类型很少使用的代码路径中的错误。没有静态类型检查,甚至100%代码覆盖率测试覆盖范围可能无法找到类型错误。代码覆盖率测试可能无法检测到此类类型错误因为所有地方的组合在那里创造价值和所有使用某个值的地方必须考虑到

最广泛使用的静态类型语言不是正式的类型安全的。他们有“漏洞”在程序设计语言规范使程序员能够编写代码可以绕过验证由静态类型检查器执行并且从而解决更广泛的问题。例如,Java和大多数C风格语言有类型双关语,并且Haskell具有以下特性不安全PerformIO:此类操作可能在运行时是不安全的,因为它们可以导致不必要的行为错误键入值时程序运行。

动态类型

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

动态类型可能导致运行时类型错误-即,在运行时,a值可能具有意外的类型,并且对那种人来说是荒谬的已应用。此操作可能会发生很久以后的地方编程错误犯了-也就是说,错误数据类型的地方进入了一个不该去的地方这使得bug难以定位。

动态类型语言系统,与静态类型相比表兄弟,减少“编译时”检查源代码(但会例如,检查程序语法正确)。运行时支票可能会更多复杂的,因为他们可以使用动态信息以及任何期间出现的信息汇编。另一方面,运行时检查仅断言条件在特定执行程序,而这些每个人都要重复检查执行程序。

动态类型开发语言通常由编程实践,如单元测试。测试是专业软件开发,以及在动态类型语言。在实践中,测试完成,以确保正确的程序操作可以检测到比静态更广泛的错误范围类型检查,但反过来不能全面搜索该测试和静态的错误类型检查能够检测到。测试可以纳入软件构建周期,在这种情况下可以被认为是“编译时”检查,因为程序用户将不需要手动运行这样的测试。

参考文献

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

静态类型语言

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

这里的主要优点是编译器可以完成各种检查,因此在很早的阶段就会发现很多琐碎的错误。

示例:C、C++、Java、Rust、Go、Scala

动态类型语言

如果类型与运行时值相关联,而不是命名为变量/字段/等,则语言是动态类型的,这意味着您作为程序员可以更快地编写,因为您不必每次都指定类型(除非使用类型推断的静态类型语言)。

示例:Perl、Ruby、Python、PHP、JavaScript、Erlang

大多数脚本语言都有这个特性,因为没有编译器来做静态类型检查,但是你可能会发现自己在搜索一个bug,这是由于解释器误解了变量的类型。幸运的是,脚本往往很小,所以错误没有那么多地方可以隐藏。

大多数动态类型语言确实允许您提供类型信息,但不需要它。目前正在开发的一种语言流氓采用混合方法,允许在函数中使用动态类型,但对函数签名强制执行静态类型。

类型检查是验证和执行类型约束的过程。

  • 静态类型编程语言在编译时间处进行类型检查。示例:Java,C,C++。

  • 动态类型编程语言在运行时间处进行类型检查。示例:Perl、Ruby、Python、PHP、JavaScript。

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

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

对于ex. int x; x=10;

System.out.println(x);

动态类型:Perl是一种动态类型语言。

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

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

下面是一个对比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'

因为相关的线路实际上被执行了。

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

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)

不幸的是,术语“动态类型”具有误导性。所有语言都是静态类型的,类型是表达式的属性(而不是某些人认为的值)。然而,有些语言只有一种类型。这些被称为单类型语言。这种语言的一个例子是无类型lambda演算。

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

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

执行此操作的单类型语言称为动态类型语言。

JavaScript、Python和Ruby等语言都是单类型的。同样,JavaScript中的typeof运算符和Python中的type函数有误导性的名称;它们返回与操作数关联的标签,而不是它们的类型。类似地,C++中的dynamic_cast和Java中的instanceof做了没有的类型检查。

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

例如Java:

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

另一方面:在动态类型语言中,变量的类型是动态,这意味着在将变量设置为类型后,您可以更改它。这是因为类型与它假定的值相关联,而不是变量本身。

例如在Python中:

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

因此,最好将动态类型语言中的变量视为类型化值的只是泛型指针

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

静态类型语言通常是编译语言,因此,编译器检查类型(这很有意义,对吧?因为类型不允许稍后在运行时更改)。

动态类型语言通常是被解释的,因此类型检查(如果有的话)会在运行时使用它们。这当然会带来一些性能成本,这也是动态语言(例如python、ruby、php)扩展不如类型化语言(java、c#等)的原因之一。从另一个角度来看,静态类型语言有更多的启动成本:让你通常编写更多代码、更难的代码。但这以后会得到回报。

好消息是双方都在借鉴对方的特性。类型化语言正在整合更多的动态特性,例如c#中的泛型和动态库,而动态语言正在包括更多的类型检查,例如python中的类型注释,或PHP的HACK变体,这些通常不是语言的核心,可以按需使用。

当谈到技术选型时,任何一方都没有内在的优势。你是想从一开始就有更多的控制权还是灵活性,这只是一个偏好问题。只要为工作选择合适的工具,并确保在考虑转换之前检查相反的方面有什么可用的。

静态类型语言在编译时进行类型检查,类型不能更改。(不要对类型转换注释感到可爱,会创建一个新的变量/引用)。

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

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

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

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

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

例子:C、C++、Java

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

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

示例:Ruby、Python。

编译vs.解释

“当源代码被翻译时”

  • 源代码:原始代码(通常由人输入计算机)
  • 翻译:将源代码转换为计算机可以读取的东西(即机器代码)
  • 运行时间:程序执行命令的时期(编译后,如果编译)
  • 编译语言:在运行时之前翻译的代码
  • 口译语言:在执行期间动态翻译的代码

打字

"当类型被检查时"

5 + '3'强类型语言(如Go和Python)中类型错误的一个示例,因为它们不允许“类型强制转换”->值在某些上下文中更改类型的能力,例如合并两个类型。

  • 静态:在运行时之前检查类型
  • 动态:在执行期间动态检查类型

“静态和编译”和“动态和解释”的定义非常相似……但请记住它是“检查类型时”与“翻译源代码时”。

无论语言是编译还是解释,您都会得到相同的类型错误!你需要从概念上分离这些术语。


python示例

动态,解释

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

因为Python既是解释型的又是动态类型的,所以它只翻译和类型检查它正在执行的代码。else块永远不会执行,所以5 + '3'甚至永远不会被看到!

如果它是静态类型的呢?

在代码运行之前会抛出类型错误。即使它被解释,它仍然会在运行时之前执行类型检查。

如果它是编译的呢?

else块将在运行时之前被翻译/查看,但因为它是动态类型的,所以不会抛出错误!动态类型语言在执行之前不会检查类型,并且该行永远不会执行。


Go示例

静态,编译

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

类型在运行前检查(静态),类型错误立即被捕获!如果解释类型,仍然会在运行时之前检查类型,结果相同。如果它是动态的,即使在编译期间会查看代码,它也不会抛出任何错误。


性能

如果编译语言是静态类型的(与动态类型相比),它在运行时将具有更好的性能;类型知识允许机器代码优化。

静态类型语言在运行时本质上具有更好的性能,因为不需要在执行时动态检查类型(它在运行前检查)。

类似地,编译语言在运行时更快,因为代码已经被翻译,而不需要动态“解释”/翻译。

请注意,编译语言和静态类型语言在分别运行翻译和类型检查之前都会有延迟。


更多差异

静态类型会及早发现错误,而不是在执行过程中发现错误(尤其对长程序有用)。它更“严格”,因为它不允许程序中的任何地方出现类型错误,并经常阻止变量更改类型,这进一步防止了意外错误。

num = 2num = '3' // ERROR

动态类型更灵活,有些人对此表示赞赏。它通常允许变量更改类型,这可能会导致意外错误。

动态类型语言有助于快速构建算法概念的原型,而无需考虑需要使用哪些变量类型(这在静态类型语言e中是必要的)。

静态类型语言(如C++、Java)和动态类型语言(如Python)仅在变量类型的执行方面有所不同。静态类型的语言对变量有静态数据类型,这里的数据类型是在编译过程中检查的,所以调试要简单得多……而动态类型语言没有这样做,检查执行程序的数据类型,因此调试有点困难。

此外,它们有非常小的差异,可以与强类型弱类型语言相关。强类型语言不允许您将一种类型用作另一种类型,例如C和C++…而弱类型语言允许eg.python

静态类型语言(编译器解析方法调用和编译引用):

  • 通常更好的性能
  • 更快的编译错误反馈
  • 更好的IDE支持
  • 不适合处理未定义的数据格式
  • 当模型未定义时更难启动开发
  • 更长的编译时间
  • 在许多情况下需要编写更多代码

动态类型语言(在运行程序时做出的决定):

  • 性能较低
  • 更快的发展
  • 某些错误可能仅在运行时稍后才会被检测到
  • 适用于未定义的数据格式(元编程)

静态类型

在运行时之前检查类型,因此可以更早地捕获错误。

例子=c++

动态类型

在执行期间检查类型。

示例=Python

静态类型:在编译时执行的类型检查

静态类型语言的真正含义:

  • 必须指定变量的类型
  • 变量只能引用特定类型的对象*
  • 值的类型检查将在编译时执行,届时将报告任何类型检查
  • 内存将在编译时分配以存储该特定类型的值

静态类型语言的示例有C、C++Java。

动态类型:在运行时执行的类型检查

动态类型语言的真正含义:

  • 不需要指定变量的类型
  • 同一个变量可以引用不同类型的对象

Python、Ruby是动态类型语言的例子。


*一些对象可以通过类型转换分配给不同类型的变量(C和C++等语言中非常常见的做法)

动态类型编程,允许程序在运行时更改变量的类型。

动态类型语言:Perl、Ruby、python、PHP、javascript、Erlang输入图片描述

静态类型,表示如果您尝试将字符串存储在整数变量中,它将不接受它。

静态类型语言:C、C++、Java、Rust、Go、Scala、Dart输入图片描述

在编程中,数据类型是一种分类告诉变量将持有什么类型的值以及可以对这些值进行数学、关系和逻辑操作而不会出错。

在每种编程语言中,为了尽量减少出错的机会,在程序执行之前或期间进行类型检查。取决于类型检查的时间编程语言有两种类型:静态类型动态类型语言。

还有取决于是否隐式类型转换是否发生,编程语言有2种:强类型弱类型语言。

类型-静态vs动态,强vs弱

静态类型:

  • 类型检查在编译时完成

  • 在源代码中,在变量声明时,必须显式指定该变量的数据类型。因为如果在源代码中指定了数据类型,那么在编译时源代码将转换为机器代码并且可以进行类型检查

  • 这里数据类型与变量相关联喜欢,int count。这个关联是静态的或固定的

  • 如果我们尝试通过分配其他数据类型(int count = "Hello")的值来更改已声明变量(int count)的数据类型,那么我们将收到错误

  • 如果我们尝试通过使用其他数据类型(boolean count)重新声明已经声明的变量(int count)来更改数据类型,那么我们也会得到错误

int count;         /* count is int type, association between data typeand variable is static or fixed */
count = 10;        // no errorcount = 'Hello';   // errorboolean count;     // error
  • 由于类型检查和类型错误检测是在编译时完成的,这就是为什么在运行时不需要进一步的类型检查。因此程序变得更加优化,导致更快的执行

  • 如果我们想要更严格的代码,那么选择这种类型的语言是更好的选择

  • 示例:Java、C、C++、Go、Swift等。

动态类型:

  • 类型检查在运行时完成

  • 在源代码中,在变量声明时,不需要显式指定该变量的数据类型。因为在运行时的类型检查期间,语言系统从赋值给该变量的数据类型确定变量类型

  • 这里数据类型与分配给变量的值相关联喜欢,var foo = 10,10是一个数字,所以现在foo是数字数据类型。但这种关联是动态或灵活的

  • 我们可以很容易地更改已经声明的变量(var foo = 10)的数据类型,通过将其他数据类型(foo = "Hi")的值分配给它,没有错误

  • 我们可以很容易地更改已声明变量(var foo = 10)的数据类型,通过使用其他数据类型(var foo = true)的值重新声明它,没有错误

var foo;            // without assigned value, variable holds undefined data type
var foo = 10;       // foo is Number type now, association between data// type and value is dynamic / flexiblefoo = 'Hi';         // foo is String type now, no errorvar foo = true;     // foo is Boolean type now, no error
  • 由于类型检查和类型错误检测是在运行时完成的,这就是为什么程序变得不那么优化,导致执行速度较慢的原因。尽管如果实现JIT编译器,这些类型的语言的执行可以更快

  • 如果我们想轻松编写和执行代码,那么这种类型的语言是更好的选择,但在这里我们会遇到运行时错误

  • 示例:Python、JavaScript、PHP、Ruby等。