静态/动态与强/弱


319

我看到这些术语在编程中无处不在,我对它们的含义有一个模糊的概念。搜索显示我实际上已经在整个堆栈溢出中询问了此类问题。据我所知,语言中的静态/动态键入与强/弱键入有细微的区别,但是这种差异是我难以理解的。不同的来源似乎使用不同的含义,甚至可以互换使用这些术语。我找不到某个地方可以同时谈论这两者,并能说明差异。最好的是,如果有人可以在这里为我和世界其他地方清楚地说明这一点。



Answers:


423
  • 静态/动态打字为约类型信息被获取(无论是在编译时或在运行时)

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

有关更多详细信息,请参见Wiki页面


7
维基百科提供了所有答案。我不知道为什么我没有偶然发现这一点。
丹·雷维尔

31
很可惜,许多人没有意识到静态/动态不是强/弱...……这确实可以节省一些偏见和讨论。
Dykam

10
有不同程度的“类型弱点”。一种强类型的语言可能会尝试从字符串到数字的转换。另一方面,HyperTalk(我几十年前使用的一种语言)的类型很弱,"12" + "34"因此等于"46",但"12" + "34Q"等于"1234Q"[幸运的是,"12" & "34"如果有人想要串联,则可以编写]。奇怪的是,保存数字的变量将它们存储为双精度浮点数,并且此类变量的数学运算使用浮点值而不用字符串修饰,但是无法询问变量是字符串还是数字。
supercat 2012年

9
@kittylyst我看不出这个答案在哪里表明strong是静态的同义词
Pete

4
++(大致)用于单行定义。
JamesFaix

211

您已经发现业余爱好者用来谈论编程语言的术语上的薄弱之处。 请勿使用“强”和“弱”类型的术语,因为它们在技术含义上尚未达成共识。相比之下,静态类型化意味着在执行程序之前先检查程序,然后在启动程序之前将其拒绝。 动态类型化意味着执行过程中会检查的类型,而类型错误的操作可能会导致程序停止运行在运行时发出错误信号。静态类型化的主要原因是要排除可能具有此类“动态类型错误”的程序。

强类型通常意味着类型系统中没有漏洞,而弱类型意味着类型系统可以被破坏(使任何保证无效)。这些术语经常被错误地使用来表示静态和动态类型。要了解它们之间的区别,请考虑一下C:在编译时对语言进行类型检查(静态类型化),但是存在很多漏洞;您几乎可以将任何类型的值转换为相同大小的另一类型-特别是,您可以自由地转换指针类型。帕斯卡(Pascal)是一种旨在强力打字的语言,但著名的是无法预料的漏洞:没有标签的变体记录。

强类型语言的实现通常会随着时间的流逝而产生漏洞,因此,可以使用高级语言来实现部分运行时系统。例如,Objective Caml有一个称为的函数Obj.magic,具有仅返回其参数的运行时效果,但是在编译时,它将任何类型的值转换为任何其他类型的值。我最喜欢的示例是Modula-3,其设计者将其称为类型转换构造LOOPHOLE

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


31
(+1),建议您避免使用术语“强”和“弱”。
Nico

1
同意,只是读过乔恩·斯凯特(Jon Skeet)的书,这与那里的回答相同。
Bennett Yeates

据我所知,Java也有这些漏洞,但是它仍然被认为是一种强类型的语言,因此我认为这更有助于您避免使用“强”和“弱”一词的建议。
doubleOrt

74

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

例如在Java中:

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

而在动态类型语言中,类型是dynamic,这意味着在将变量设置为类型之后,可以对其进行更改。这是因为键入与值而不是变量相关联。

例如在Python中:

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

另一方面,某种语言的强/弱键入与隐式类型转换有关(部分取自@Dario的答案):

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

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


2
很好的答案,并使用具体示例表示敬意。
朱利安·

3
这就是为什么需要谨慎使用PHP的原因。
阿里·加贾尼

1
语言示例确实很有帮助。非常感激。
J马伦

从这个意义上讲,Java的类型会变得如此微弱,因为您可以将非字符串与字符串连接起来,并且由于自动拆箱/装箱?
斯蒂芬·保罗

1
@StephenPaul你是对的,我的回答可能是这样理解的,事实并非如此。为了简单起见,我使用了级联,但是实际上,强弱是关于变量本身的隐式类型转换。
mehmet '19

20

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

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

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

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

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

同样,大多数强类型语言仍将在整数和浮点数之间自动转换(在某些语言中为任意精度BigInts)。


1
我不同意这句话-。“在静态类型语言中,必须在源中声明每个变量和参数的类型” –在SML中,不必声明变量的类型(无论如何检查)。可以说函数f接受参数xfun f(x))[**,所以没有声明任何类型**],函数主体为x+1。没有声明任何类型,编译器会弄清楚这x必须是一个int。- fun f x = x + 1; val f = fn : int -> int
Filip Bartuzi 2014年

关于C,强制转换并不反对强类型化,但是C允许添加不同类型而无需强制转换,例如:5 + 'c' // OK
mehmet

3
@mehmet:在C语言中,字符值位于整数域中,因此特定示例不会违反类型安全性。'c'只是99的语法糖。C没有专用的字符类型。
Peter Lewerin

彼得·勒维林(Peter Lewerin):对,我应该举一个更好的例子。不幸的是,

1
C不是弱类型语言。与C相比,只是Java,C#等是更强类型化的语言。在此处了解更多-en.wikipedia.org/wiki/Strong_and_weak_typing 如果您检查“弱”类型语言的定义,则检查“弱”类型语言的定义可以进行任何类型转换的函数,例如可以将int 隐式转换或转换为字符串的int ,现在请自己考虑一下是否可以在C中进行转换?
hagrawal

15

今天,研究这个课题我碰到这篇大文章来http://blogs.perl.org/users/ovid/2010/08/what-to-know-before-debating-type-systems.html它清除了很多对我而言,我认为这可能会增加上面的一些出色答案。

强弱键入:

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

静态和动态类型

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

静态类型系统是一种机制,编译器通过该机制检查源代码,并为语法的各个部分分配标签(称为“类型”),然后使用它们来推断有关程序行为的信息。动态类型系统是一种机制,通过该机制编译器可以生成代码来跟踪程序使用的数据种类(巧合的是,也称为“类型”)。当然,在这两个系统中的每个词上使用相同的“类型”一词并不是完全偶然的。但最好的理解是,它具有某种薄弱的历史意义。试图找到一种世界观,其中“类型”在两个系统中实际上意味着相同的东西,从而造成极大的混乱。没有。

显式/隐式类型:

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


8

从Scott的《Programming Language Pragmatics》,第3版,第291页,

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

举几个例子:Ada是强类型的,并且在大多数情况下是静态类型的(必须在运行时检查某些类型的约束)。Pascal实现也可以在编译时进行大多数类型检查,尽管该语言的类型不是很严格:未标记的变体记录(将在第7.3.4节中讨论)是唯一的漏洞。C89的打字强度明显高于其前身方言,但打字强度却远低于Pascal。它的漏洞包括并集,带有可变数量参数的子例程以及指针和数组的互操作性(将在第7.7.1节中讨论)。C的实现很少在运行时检查任何内容。

动态(运行时)类型检查是后期绑定的一种形式,并且倾向于在将其他问题推迟到运行时的语言中找到。Lisp和Smalltalk是动态(尽管很强)类型的。大多数脚本语言也可以动态键入。有些(例如Python和Ruby)是强类型的。具有动态作用域的语言通常是动态键入的(或根本不键入):如果编译器无法识别名称所引用的对象,则通常也无法确定对象的类型。

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

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

静态/动态-强/弱键入平面


5

我认为其他同事尤其出色。说明静态类型和动态类型之间的区别。但是就强类型和弱类型而言,应该说存在不同的理解/观点。

这里有两个例子:

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

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

两种说法都没有强调类型系统的相反极端,而是强调完全不同的方面。因此,我同意拉姆齐先生的观点,即不要使用术语“强”和“弱”来区分类型系统。


5

静态v / s动态类型语言

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

强烈反对弱类型语言

  • 强类型语言是在精度下降的情况下不允许进行隐式转换的语言。例如,在Java中,可以将“ int转换为long”,因为不会损失精度,但不能“隐式”转换“ long to int”,因为会损失精度。相反,在弱类型语言中,即使损失精度也允许隐式转换。
  • 我认为动态类型语言也可以是强类型语言,如果“在运行时”不允许隐式转换而导致精度下降的话。

良好的进一步阅读


您引用了“现在在运行时,如果没有类型检查,那么我可以传递我自己的类的对象,该对象具有相同的方法” creditAccount(BankAccountDetails)”-如果您已经超越了可能阻止您传递对象的机制那么如果使用静态类型的语言,类型检查将如何阻止您调用该方法?
Aseem Yadav

@AseemYadav“ *如果您已经超越了可能阻止您传递对象的机制*”,这是什么意思?
hagrawal

正如您提到的那样,它是一项重要的安全功能,并且您可以使用相同的方法传递您自己的类的对象,因此对我而言,这意味着,当您尝试闯入他人的代码时,它似乎只是一个漏洞而已。如果您说的是属于您的代码,而不是与安全性相关的性能问题,不是吗?
Aseem Yadav

它没有性能方面的内容,您必须从多态性的上下文中查看它,然后您才能了解它的安全方面,我在同一段中已经提到了这一点。
hagrawal

1

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

动态类型的语言通常不需要变量声明具有类型,并且它们根据对每个赋值语句的右侧或函数调用的实际参数求值而得出的类型来推断变量类型。由于可以在变量的整个生命周期内对其进行多次分配,因此其类型可以随时间变化,这就是为什么将其称为“动态类型”。另外,运行时环境需要跟踪每个变量的当前类型,因此类型绑定到值,而不是变量声明。可以将其视为运行时类型信息(RTTI)系统。

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

强类型与弱类型是指语言试图防止由于使用变量而导致的错误的连续性,就像实际上是另一种类型一样。例如,C和Java都是静态类型的语言,但是Java比C使用更强的类型检查。以下C代码很乐意编译和运行,并且会在运行时将随机值放入变量b中,很可能导致错误:

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

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

String a = "123"
int b = (int)a;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.