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

Posted

技术标签:

【中文标题】静态类型语言和动态类型语言有啥区别?【英文标题】:What is the difference between statically typed and dynamically typed languages?静态类型语言和动态类型语言有什么区别? 【发布时间】:2010-12-03 19:21:16 【问题描述】:

我经常听说新的编程语言是动态类型的,但是当我们说一种语言是动态类型与静态类型时,这实际上意味着什么?

【问题讨论】:

@EricLeschinski 我认为单元测试现在可以帮助解决这个问题,并且可以对诸如 javascript 之类的动态类型语言进行编码,并且可以放心地对其进行编码,从而使其有资格用于企业软件开发,你不觉得吗? 在最好的情况下,这些单元测试会随着时间的推移而恶化,并被试图提高工作安全性的同事关闭,最坏的情况是,它们从一开始就没有被编写出来。这就像建议专业机械师在客户的汽车上使用胶带。是的,初级,在这个传输工作中使用胶带是个好主意……对你来说。 android.jlelse.eu/… 也可能有用 【参考方案1】:

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

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

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

动态类型语言的示例是:- Perl、Ruby、Python、php、JavaScript

【讨论】:

我认为这是最好的答案。特别是,接受的答案在很大程度上实际上是不正确的。 @JonHarrop 具体在哪些方面? @thomas:“这意味着你作为程序员可以写得更快一点,因为你不必每次都指定类型”。如果您有类型推断,则不必每次都使用静态类型指定类型。参见 SML、OCaml、F#、Haskell... 在静态类型的 prog 语言中,类型检查在运行前完成,但不完全在编译时完成。【参考方案2】:

静态类型语言

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

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

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

动态类型语言

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

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

大多数脚本语言都具有此功能,因为无论如何都没有编译器来进行静态类型检查,但是您可能会发现自己正在寻找由于解释器误解变量类型而导致的错误。幸运的是,脚本往往很小,所以 bug 没有太多可以隐藏的地方。

大多数动态类型语言都允许您提供类型信息,但并不要求提供。目前正在开发的一种语言 Rascal 采用混合方法,允许在函数内进行动态类型化,但对函数签名强制执行静态类型化。

【讨论】:

@NomeN 你能说出任何实现 HM 类型推断的动态类型语言吗? “如果变量的类型在运行时被解释,则语言是动态类型的”:否。如果类型与运行时值相关联,而不是命名变量/字段,则语言是动态类型的/等等。 不正确,静态类型意味着“引用值明显(与编译时不同)受限于它可以表示的值的类型,并且语言实现,无论是编译器还是解释器,都尽可能地执行和使用这些约束。”引用自:c2.com/cgi/wiki?StaticTyping,我的理解是正确的。 Java、C、C++、Pascal 和许多其他广泛使用的“工业”语言的类型系统最明显的一点不是它们是静态类型的,而是它们是显式类型的。换句话说,它们需要大量的类型声明。 (在非显式类型语言的世界中,这些声明是可选的,它们通常被称为“类型注释”。)这与静态类型无关。继续.. 第一个静态类型语言是根据需要显式类型化的。然而,类型推断算法——在根本没有类型声明的情况下查看源代码并确定其变量类型的技术已经存在多年了。使用它的 ML 语言。 Haskell 对其进行了改进,现在已经有 15 年的历史了。甚至 C# 现在也采用了这个想法,这会引起很多人的注意,并且无疑会引起人们对它“弱类型”的说法。继续...【参考方案3】:

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

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

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

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

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

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

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

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


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

【讨论】:

【参考方案4】:

静态类型

在运行前检查类型,以便更早发现错误。

示例 = c++

动态类型

在执行期间检查类型。

示例 = Python

【讨论】:

这并没有真正添加其他答案尚未涵盖的任何内容,是吗? 是的,但大多数答案都不是很清楚,所以我想要一个易于理解的答案。【参考方案5】:

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

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

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

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

【讨论】:

【参考方案6】:

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

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

示例:C、C++、Java

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

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

示例:Ruby、Python。

【讨论】:

【参考方案7】:

静态类型语言(如 C++、Java)和动态类型语言(如 Python)仅在变量类型的执行方面有所不同。 静态类型语言具有变量的静态数据类型,这里在编译期间检查数据类型,因此调试更加简单......而动态类型语言不这样做同样,检查执行程序的数据类型,因此调试有点困难。

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

【讨论】:

【参考方案8】:

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

【讨论】:

【参考方案9】:

编译与解释

“当源代码被翻译时”

源代码:原始代码(通常由人输入计算机) 翻译:将源代码转换为计算机可以读取的内容(即机器码) Run-Time:程序执行命令的时间段(编译后,如果已编译) 编译语言:在运行前翻译代码 解释语言:在执行期间动态翻译代码

打字

“检查类型时”

5 + '3' 是 Go 和 Python 等 强类型 语言中的类型错误示例,因为它们不允许“类型强制” -> 值更改的能力在某些上下文中键入,例如合并两种类型。 弱类型语言,例如 JavaScript,不会引发类型错误(导致 '53')。

静态:运行前检查的类型 动态:在执行期间动态检查类型

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

无论该语言是编译型还是解释型,都会出现相同类型的错误!您需要在概念上区分这些术语。


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 = 2
num = '3' // ERROR

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

【讨论】:

"因为 Python 既是解释型的又是动态类型的,它只翻译和类型检查它正在执行的代码"——事实并非如此。 Python(至少是参考实现)在导入时编译所有代码(您也可以在导入模块之前/不导入它们)。编译器引入了各种优化(至少在 Python 的动态特性允许的范围内)。【参考方案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)

【讨论】:

感谢您提供的整洁示例。所以我推断所有的脚本语言都是动态类型的,因为它们没有被编译? 是的。所有脚本语言都是动态类型的,因为它们无论如何都没有编译器来进行静态类型检查。这一点在这篇文章sitepoint.com/typing-versus-dynamic-typing中已经说明了。 Scala 可以用作脚本语言,它是静态类型的! #discussion @Shashi @Shashi 编译并不意味着静态类型。例如,Haskell 可以用 runhaskell 解释。 另外脚本语言并不意味着解释语言。 TypeScript 是静态类型的、编译/转译的,但是是脚本语言。【参考方案11】:

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

例如在 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

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

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

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

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

好消息是双方都在借鉴对方的功能。类型化语言正在包含更多动态特性,例如 c# 中的泛型和动态库,而动态语言包含更多类型检查,例如 python 中的类型注释或 PHP 的 HACK 变体,它们通常不是语言的核心,可用于要求。

在技术选择方面,任何一方都没有天生的优势。您是否想要更多的控制或灵活性只是一个偏好问题。只需为工作选择正确的工具,并确保在考虑转换之前检查可用的相反工具。

【讨论】:

这很有意义。我认为它至少比这里的其他答案更好地解释了名称背后的原因。 Lucas,与此相反,该文档不断重复 Python 是强类型和动态类型的。你在哪里看到的?可以报​​价吗? 我认为这个答案最能以最简单的方式传达这个概念。许多其他答案试图抽象地描述这个概念,但在某些细节上失败了。我宁愿在列表顶部看到这个答案。 大多数其他答案在我脑海中产生了更多问题。这一个清除了所有这些。恕我直言,这个答案确实应该排在首位 我认为“打字”这个词会妨碍清晰度。你的回答让我明白了:) 每次我过去听到这个,我都在想在键盘上打字,就像你声明或不声明变量的方式有关;我从来没有想过数据类型。所以“类型化”是指变量的数据类型改变状态的能力,无论变量的数据类型是静态的还是动态的。前任。动态(Str -> int -> Boolean)【参考方案12】:

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

【讨论】:

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

【讨论】:

【参考方案14】:

静态类型语言在编译时进行类型检查,类型不能改变。 (不要因为类型转换 cmets 而变得可爱,会创建一个新变量/引用)。

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

【讨论】:

【参考方案15】:

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

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

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

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

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

【讨论】:

想象用一个让我们再问十个问题的回答来回答这个问题......【参考方案16】:

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

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

例如。诠释 x; x = 10;

System.out.println(x);

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

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

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

【讨论】:

嗯,这个答案并不完全正确。在这两种语言中,变量必须在使用之前进行初始化。但是,在动态类型语言中,您可以选择省略使用它的类型。 您似乎误用了“变量”一词,您应该改用“类型”。 我认为 Perl 是静态类型的:它有 3 种类型,标量 ($)、数组 (@) 和哈希 (%)。 Perl 中变量的类型在编译时是已知的,并且在变量的其余生命周期内保持不变。【参考方案17】:

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

静态输入

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

因为他们评估类型信息 在编译期间,因此缺乏 类型信息仅 在运行时可用,静态类型 跳棋是保守的。他们将 拒绝一些可能的程序 在运行时表现良好,但是 不能静态确定为 好排版。例如,即使一个 总是表达 在运行时计算为真,a 包含代码的程序

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

将被拒绝为错误类型,因为 静态分析无法确定 else 分支不会是 [1]保守的行为 静态类型检查器是 有利时 很少评估为假:A 静态类型检查器可以检测类型 很少使用的代码路径中的错误。 没有静态类型检查,即使 100% 代码的代码覆盖率测试 覆盖面可能无法找到这样的 类型错误。代码覆盖测试可能 未能检测到此类类型错误 因为所有地方的结合 创造价值的地方和所有 使用特定值的地方 必须考虑在内。

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

动态输入

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

动态输入可能会导致运行时 类型错误——也就是说,在运行时,一个 value 可能具有意外的类型,并且 该类型的操作无意义 被申请;被应用。可能会出现此操作 很久以后 犯了编程错误——也就是说, 数据类型错误的地方 进入不应该的地方 有。这使得该错误难以 定位。

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

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

参考文献

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

【讨论】:

这似乎是多余的,因为它是***的链接,而不是一些临时网站,但我下次会记住的。 不知何故,我仍然想不出动态类型语言中的示例,其中类型在编译时不清楚,但必须在运行时弄清楚。能给我一些吗? @Novellizator 旧评论,但想象一下从远程服务器获取一些数据然后使用该数据从对象中获取属性的场景。例如:myObject[remoteDataName]。那么就无法知道它将选择哪个属性,甚至根本无法知道它是否是有效属性。

以上是关于静态类型语言和动态类型语言有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

静态语言和动态语言的区别(转)

什么是动态语言和静态语言?静态语言动态语言的区别

编译型语言解释型语言静态类型语言动态类型语言概念与区别

编译型语言解释型语言静态类型语言动态类型语言概念 与 区别

静态语言 与 动态语言 的区别

编译型语言解释型语言静态类型语言动态类型语言概念与区别