349

我看到这些术语在编程中到处都是,我对它们的含义有一个模糊的概念。搜索显示,实际上在堆栈溢出中已经询问过这样的事情。据我所知,语言中的静态/动态输入与强/弱输入略有不同,但我不知道这种差异是什么。不同的来源似乎使用不同的含义,甚至可以互换使用这些术语。我找不到可以谈论两者并实际上说明差异的地方。如果有人可以在这里为我和世界其他地方清楚地说明这一点,那就太好了。

4

10 回答 10

457
  • 静态/动态类型是关于何时获取类型信息(在编译时或运行时)

  • 强/弱类型是关于如何严格区分类型(例如,语言是否尝试进行从字符串到数字的隐式转换)。

有关更多详细信息,请参阅wiki 页面

于 2010-02-28T13:46:31.737 回答
223

您在业余爱好者用来谈论编程语言的术语中发现了一个软肋。 不要使用术语“强”和“弱”类型,因为它们没有普遍认可的技术含义。相比之下,静态类型意味着程序在执行之前会被检查,并且程序在启动之前可能会被拒绝。 动态类型意味着执行期间检查的类型,并且类型不佳的操作可能会导致程序停止或在运行时发出错误信号。静态类型的一个主要原因是排除可能有这种“动态类型错误”的程序。

强类型一般意味着类型系统没有漏洞,而弱类型意味着类型系统可以被颠覆(使任何保证失效)。这些术语经常被错误地用于表示静态和动态类型。要看到区别,想想 C:该语言在编译时进行类型检查(静态类型),但有很多漏洞;您几乎可以将任何类型的值转换为相同大小的另一种类型——特别是,您可以自由地转换指针类型。Pascal 是一种旨在进行强类型化的语言,但众所周知的是有一个无法预料的漏洞:没有标签的变体记录。

随着时间的推移,强类型语言的实现经常会出现漏洞,通常使得运行时系统的一部分可以用高级语言实现。例如,Objective Caml 有一个被调用的函数Obj.magic,它具有简单地返回其参数的运行时效果,但在编译时它将任何类型的值转换为任何其他类型的值。我最喜欢的例子是 Modula-3,其设计者将他们的类型转换构造称为LOOPHOLE

话虽如此,你不能指望任何两个人以完全相同的方式使用“强”和“弱”这两个词。所以避免他们。

于 2010-02-28T17:30:37.327 回答
84

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

例如在 Java 中:

String str = "Hello";  //statically typed as string
str = 5;               //would throw an error since java is statically typed

而在动态类型语言中,类型是动态的,这意味着在将变量设置为类型之后,您可以更改它。这是因为类型与值相关联,而不是与变量相关联。

例如在 Python 中:

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

另一方面,语言中的强/弱类型与隐式类型转换有关(部分取自@Dario's answer):

例如在 Python 中:

str = 5 + "hello" 
# would throw an error since it does not want to cast one type to the other implicitly. 

而在 PHP 中:

$str = 5 + "hello"; // equals 5 because "hello" is implicitly casted to 0 
// PHP is weakly typed, thus is a very forgiving language.

静态类型允许在编译时检查类型的正确性。静态类型语言通常被编译,而动态类型语言被解释。因此,动态类型语言可以在运行时检查类型。

于 2015-11-30T17:46:45.617 回答
21

弱类型化意味着对象的类型可以根据上下文而改变。例如,在弱类型语言中,如果您向其添加另一个数字,则字符串“123”可能会被视为数字 123。弱类型语言的例子有 bash、awk 和 PHP。

另一种弱类型语言是 C,其中内存地址处的数据可以通过强制转换被视为不同的类型。

在强类型语言中,对象的类型不会改变 - int 始终是 int 并且尝试将其用作字符串将导致错误。Java 和 Python 都是强类型的。

动态类型和静态类型之间的区别在于强制执行类型规则的时间。在静态类型语言中,每个变量和参数的类型必须在源代码中声明并在编译时强制执行。在动态类型语言中,只有在运行时使用类型时才会检查类型。所以Java是静态类型的,Python是动态类型的。

然而,有时界限可能有点模糊。例如,尽管 Java 是静态类型的,但每次您使用反射或强制转换(例如,当使用对象容器时)时,您都将类型检查推迟到运行时。

类似地,大多数强类型语言仍然会在整数和浮点数之间自动转换(在某些语言中是任意精度的 BigInts)。

于 2010-02-28T13:56:19.630 回答
16

今天研究这个主题,我发现了这篇很棒的文章http://blogs.perl.org/users/ovid/2010/08/what-to-know-before-debating-type-systems.html它清除了很多对我来说,我认为这可能会增加上面的一些很好的答案。

强类型和弱类型:

可能最常见的类型系统分类方式是“强”或“弱”。这是不幸的,因为这些词几乎没有任何意义。在有限的范围内,可以将两种语言与非常相似的类型系统进行比较,并指定一种语言具有这两种系统中更强的一种。除此之外,这些话根本没有任何意义。

静态和动态类型

这几乎是唯一具有实际意义的类型系统的常见分类。事实上,它的重要性经常被低估 [...] 动态和静态类型系统是两个完全不同的东西,它们的目标恰好部分重叠。

静态类型系统是一种机制,编译器通过该机制检查源代码并将标签(称为“类型”)分配给语法片段,然后使用它们来推断程序的行为。动态类型系统是一种机制,编译器通过该机制生成代码以跟踪程序使用的数据类型(巧合的是,也称为“类型”)。当然,在这两个系统中使用同一个词“类型”并非完全巧合。但最好将其理解为具有某种微弱的历史意义。试图找到一种世界观,其中“类型”在两个系统中真正意味着相同的东西,导致了极大的混乱。它没有。

显式/隐式类型:

当使用这些术语时,它们指的是编译器对程序部分的静态类型进行推理的程度。所有编程语言都有某种形式的关于类型的推理。有些人比其他人拥有更多。ML 和 Haskell 具有隐式类型,因为不需要(或很少,取决于使用的语言和扩展)类型声明。Java 和 Ada 有非常明确的类型,并且不断地声明事物的类型。以上所有都具有(例如,相对于 C 和 C++)强静态类型系统。

于 2014-03-31T00:12:35.577 回答
12

从 Scott 的Programming Language Pragmatics第 3 版第 291 页,我们有

类型检查是确保程序遵守语言的类型兼容性规则的过程。违反规则被称为类型冲突。如果一种语言以语言实现可以强制执行的方式禁止将任何操作应用于任何不打算支持该操作的对象,则该语言被称为强类型语言。如果一种语言是强类型的并且可以在编译时执行类型检查,则称该语言为静态类型。严格来说,很少有语言是静态类型的。在实践中,该术语通常适用于大多数类型检查可以在编译时执行,其余的可以在运行时执行的语言。

几个例子:Ada 是强类型的,并且大部分是静态类型的(某些类型的约束必须在运行时检查)。Pascal 实现也可以在编译时进行大部分类型检查,尽管该语言不是强类型的:未标记的变体记录(将在第 7.3.4 节中讨论)是它唯一的漏洞。C89 的类型比它的前身方言强得多,但仍然比 Pascal 弱得多。它的漏洞包括联合、带有可变数量参数的子程序以及指针和数组的互操作性(将在第 7.7.1 节中讨论)。C 的实现很少在运行时检查任何内容。

动态(运行时)类型检查是后期绑定的一种形式,并且往往出现在将其他问题也延迟到运行时的语言中。Lisp 和 Smalltalk 是动态(尽管是强)类型的。大多数脚本语言也是动态类型的。有些(例如,Python 和 Ruby)是强类型的。具有动态范围的语言通常是动态类型的(或根本没有类型的):如果编译器无法识别名称所指的对象,它通常也无法确定对象的类型。

所以简单来说,静态/动态类型是指类型检查发生的时间:静态类型的编译时间和动态语言的运行时间。同样,强/弱类型是指一种语言在执行其类型系统方面的积极程度。

我试图将 Scott 的描述翻译成一个漂亮的图表,我已经在下面发布了。

静态/动态 - 强/弱打字平面

于 2018-08-07T11:24:29.623 回答
8

静态 v/s 动态类型语言

  • 静态类型语言是在编译时进行类型检查的语言,因此这也意味着在静态类型语言中,每个变量都有一个类型,并且在整个过程中不会改变。现在,相比之下,动态类型语言是那些在运行时进行类型检查的语言,在编译时没有类型检查,所以这也意味着在动态类型语言中,可能有也可能没有与变量关联的类型, 如果一个类型是关联的,那么它可能是一个泛型类型,比如 JS 中的“var”,它对字符串和数字都适用。
    • “动态类型检查语言的实现通常将每个运行时对象与包含其类型信息的类型标记(即,对类型的引用)相关联。此运行时类型信息 (RTTI) 还可用于实现动态调度、后期绑定、向下转换、反射和类似功能。”</li>
  • 即使语言是静态类型的,它仍然可以有一些动态类型的特性,这基本上意味着在运行时也有某种类型的检查。这在类型转换中很有用。
    • “许多有用且常见的编程语言功能无法静态检查,例如向下转换。因此,许多语言将同时进行静态和动态类型检查;静态类型检查器验证它可以做什么,而动态检查器验证其余部分。”</li>
  • “有些语言允许编写非类型安全的代码。例如,在 C 语言中,程序员可以在任意两种大小相同的类型之间自由转换一个值。”</li>
  • “静态”类型语言的优点是:
    • 由于大多数类型检查是在编译时完成的,因此解释器或运行时可以全速运行,而不必担心类型。
    • 它会导致较少数量的运行时异常或与类型相关的错误,因为大多数类型检查是在编译时完成的。
  • “动态”类型语言的优点是:
    • 它们可以帮助进行极快的原型制作,因为开发人员不需要了解类型系统,因此开发人员可以轻松地创建变量并运行它,这会导致非常快速的原型制作。
  • 静态和动态类型语言列表
    • 静态:
      • 爪哇
      • C(C 是一种静态类型语言,但与 Java 相比,它的“强”类型较少,因为它允许更多的隐式转换)
      • C++
      • C#
    • 动态:
      • PERL
      • PHP
      • Python
      • JavaScript
      • 红宝石
  • 类型检查是一项重要的安全功能。假设没有类型检查,并且一个方法接受“BankAccount”类型的对象,该对象有一个名为“creditAccount(BankAccountDetails)”的方法,现在在运行时如果没有类型检查,那么我可以传递我自己的对象具有相同方法“creditAccount(BankAccountDetails)”的类,它将被执行,考虑到我们正在谈论面向对象的语言,因为 OOP 支持“多态”,而这里我们讨论的只是“多态”。因此,基本上没有强类型检查的面向对象语言(基本上意味着它支持“多态性”)可能会导致安全问题。

强类型语言与弱类型语言

  • 强类型语言是那些在精度损失时不允许隐式转换的语言。例如,在 Java 中,您可以将“int 转换为 long”,因为不会损失精度,但您不能“隐式”将“long 转换为 int”,因为会损失精度。相反,在弱类型语言中,即使存在精度损失,也允许隐式转换。
  • 我认为动态类型语言也可以是强类型语言,如果“在运行时”它不允许存在精度损失的隐式转换。

很好的进一步阅读

于 2017-02-19T19:29:57.937 回答
5

我认为其他同事做得很好,尤其是。解释静态类型和动态类型之间的区别。但就强类型和弱类型而言,应该说有不同的理解/看法。

这里举两个例子:

  • 有人说 Haskell 是强类型的,因为不允许你进行任何类型转换。

  • 其他人(例如达里奥的观点)说一种允许故意从字符串隐式转换为数字的语言是弱类型的,但甚至其他人也称这只是鸭子类型。

这两个陈述都不是突出类型系统的相反极端,而是完全不同的方面。所以我赞同 Ramsey 先生的观点,不使用“强”和“弱”这两个词来区分类型系统。

于 2011-07-28T06:08:58.937 回答
1

静态类型语言通常要求您声明变量的类型,然后在编译时对其进行检查以减少错误。“静态类型”中的“静态”一词是指“静态代码分析”,即在执行代码之前对其进行检查的过程。尽管静态类型语言可以从表达式或实际参数的右侧推断变量的类型,但实际上大多数静态类型语言都需要显式声明变量类型。

动态类型语言通常不需要变量声明具有类型,并且它们根据计算出的类型来推断变量类型,该类型是评估每个赋值语句的右侧或函数调用的实际参数的结果。由于变量可以在其生命周期内进行多次赋值,因此它的类型会随着时间而改变,这就是它被称为“动态类型”的原因。此外,运行时环境需要跟踪每个变量的当前类型,因此类型绑定到值而不是变量声明。这可以被认为是一个运行时类型信息 (RTTI) 系统。

可以组合静态和动态类型语言的元素。例如,C# 支持静态类型变量和动态类型变量,面向对象的语言通常支持向下转换类型层次结构。静态类型语言通常提供各种绕过类型检查的方法,例如使用强制转换、反射和动态调用。

强类型与弱类型是指语言试图防止错误的连续统一体,因为它使用变量,就好像它是一种类型,而实际上它是另一种类型。例如,C 和 Java 都是静态类型语言,但是 Java 使用比 C 更强的类型检查。下面的 C 代码很容易编译和运行,并且会在运行时将随机值放入变量 b 中,很可能导致 a漏洞:

char *a = "123";
int b = (int)a;

等效的 Java 代码会产生编译错误,这通常更可取:

String a = "123"
int b = (int)a;
于 2017-05-06T19:08:59.887 回答
1

来自 Addison Wesley,面向对象的分析和设计与应用程序,第 3 版,第 66 页:

强类型和弱类型与静态和动态类型的概念完全不同。强类型和弱类型是指类型一致性,而静态和动态类型是指名称与类型绑定的时间。静态类型化(也称为静态绑定或早期绑定)是指所有变量和表达式的类型在编译时是固定的;动态类型(也称为后期绑定)意味着所有变量和表达式的类型直到运行时才知道。一种语言可以是强类型和静态类型(Ada),强类型但支持动态类型(C++,Java),或无类型但支持动态类型(Smalltalk)。

于 2020-07-01T12:01:34.163 回答