静态/动态vs强/弱

静态/动态类型和强/弱类型之间的区别是什么?

84213 次浏览
  • 静态/动态类型是关于类型信息被获取时(在编译时或在运行时)

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

更多详细信息请参见wiki页面

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

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

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

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

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

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

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

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

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

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

我认为其他同事做得很好,特别是解释了静态类型和动态类型的区别。但就强类型和弱类型而言,应该说都有 不同的理解/观点。< / p >

这里有两个例子:

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

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

这两种说法强调的不是类型系统的两个极端,而是完全不同的方面。因此,我同意Ramsey先生的观点,不要用“强”和“弱”来区分类型系统。

今天在研究这个主题时,我看到了这篇很棒的文章,它为我澄清了很多事情,我认为它可能会为上面的一些伟大的答案补充。

强和弱打字:

可能类型系统最常见的分类方法是“强” 或“弱”。这是不幸的,因为这些话几乎没有 完全没有意义。在有限的范围内,比较两者是可能的 具有非常相似类型系统的语言,并指定其中一个为具有 这两个系统中较强的一个。除此之外,这些话毫无意义 。< / p >

静态和动态类型

这几乎是类型系统的唯一常见分类 这很有意义。事实上,它的意义在于 经常被低估[…]动态类型系统和静态类型系统是不同的 两件完全不同的事情,它们的目标发生了部分的变化 重叠。< / p > 静态类型系统是编译器检查的一种机制 源代码,并将标签(称为“类型”)分配给 语法,然后使用它们来推断程序的某些内容 的行为。动态类型系统是一种机制,通过它编译器 生成代码以跟踪数据的类型(巧合的是,也是 称为它的“类型”)由程序使用。同一个词的使用 当然,在这两个系统中,“type”并不是完全相同的 巧合;然而,它最好被理解为有一种软弱 历史意义。巨大的困惑产生于试图找到一个 在这种世界观中,“类型”在两者中其实是同一个意思 系统。它不是。< / p >

显式或隐式类型:

当使用这些术语时,它们指的是a 编译器将推理程序各部分的静态类型。所有 编程语言有某种形式的类型推理。一些 比别人拥有更多。ML和Haskell都有隐式类型 (或者很少,取决于所使用的语言和扩展)类型 需要声明。Java和Ada有非常明确的类型 一个是不断地声明事物的类型。以上都有 (相对于C和c++)强静态类型 系统。< / p >

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

例如,在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的回答):

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

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

静态v/s动态类型语言

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

                强v/s弱类型语言

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

                很好的进一步阅读

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

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

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

强类型和弱类型指的是语言在多大程度上试图防止由于使用变量而导致的错误,就好像它是一种类型,而实际上它是另一种类型。例如,C和Java都是静态类型语言,但是Java使用了比C强大得多的类型检查。下面的C代码很容易编译和运行,并会在运行时将一个随机值放入变量b中,很可能会导致错误:

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

等效的Java代码将产生一个编译错误,这通常是可取的:

String a = "123"
int b = (int)a;

从斯科特的编程语言语用学,第3版291页,我们有

类型检查是确保程序遵守规则的过程 语言的类型兼容性规则。违反规则是已知的 作为一种类型冲突。一种语言被称为强类型,如果它 以语言实现可以强制的方式禁止 对任何对象的任何操作的应用,而不打算这样做 支持这一行动。一种语言被称为静态类型,如果 它是强类型的,类型检查可以在编译时执行 时间。从最严格的意义上来说,很少有语言是静态的 类型的。在实践中,这些术语通常适用于语言 大多数类型检查可以在编译时执行,其余的也可以

.在运行时执行 一些例子:Ada是强类型的,在大多数情况下 静态类型(必须在运行时检查某些类型约束 时间)。Pascal实现还可以执行大部分类型检查 在编译时,尽管语言不是很强类型: untagged变体记录(将在7.3.4节中讨论)是它的 唯一的漏洞。C89的强类型明显比它的强 以前的方言,但仍然明显不如强类型 帕斯卡。它的漏洞包括联合,可变数字的子程序 参数的互操作性,指针和数组的互操作性 在7.7.1节中讨论)。C的实现很少检查

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

因此,简单来说,静态/动态类型指的是发生类型检查的时间:静态类型是编译时间,动态语言是运行时间。类似地,强/弱类型指的是一种语言在强制执行其类型系统时的积极程度。

我试着把斯科特的描述翻译成一个漂亮的图表,我贴在下面。

静态/动态-强/弱类型平面

选自Addison Wesley, 面向对象的分析与设计与应用, 3,第66页:

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

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

在每种编程语言中,为了尽量减少出错的机会,类型检查都是在程序执行之前或执行过程中进行的。根据类型检查时间,编程语言有2种类型:静态类型动态类型语言。

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

typing- static vs dynamic, strong vs weak

静态类型:

  • < p > 类型检查在编译时完成

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

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

  • 如果我们试图通过为一个已经声明的变量(int count)赋值其他数据类型(int count = "Hello")来改变它的数据类型,那么我们将得到错误

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

int count;         /* count is int type, association between data type
and variable is static or fixed */


count = 10;        // no error
count = 'Hello';   // error
boolean count;     // error
  • 由于类型检查和类型错误检测是在编译时完成的,这就是为什么在运行时不需要进一步的类型检查。因此,程序变得更加优化,结果在更快的执行

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

  • 示例:Java, C, c++, Go, Swift等

动态类型:

  • < p > 类型检查在运行时完成

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

  • 这里数据类型与赋给变量的值相关联像,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 / flexible
foo = 'Hi';         // foo is String type now, no error
var foo = true;     // foo is Boolean type now, no error
  • 由于类型检查和类型错误检测是在运行时完成的,这就是为什么程序变得不那么优化,导致执行速度变慢。尽管如果它们实现了JIT编译器,这些类型的语言的执行速度会更快

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

  • 例如:Python, JavaScript, PHP, Ruby等。

强类型:

  • 数据类型相关规则和限制是严格维护

  • 从一种数据类型转换到另一种数据类型数据类型必须显式地完成,没有隐式类型转换

# in python, "5" cannot automatically get converted to 5
pybar = "5"


print(10 + pybar)     # error, no `+` operation between `int` and `str`
  • 类型检查可以在编译时或运行时进行。这意味着强类型语言既可以是静态类型的,也可以是动态类型的

  • 示例:Python, Java, Ruby, c#等

弱类型:

  • 数据类型相关规则和限制是松散的维护

  • < p > 从一种数据类型到另一种数据类型的转换可以隐式进行

  • 如果我们在两个不匹配的数据类型的值之间执行一些操作,那么这种类型的语言可能不会抛出错误。相反,弱类型语言将应用它们自己的隐式类型转换规则,并将返回一些结果

jsbar = "5";


alert(10 + jsbar);  /* "105", no error as javascript implicitly coerces Number 10
to String "10", so that it can be concatenated with other operand jsbar i.e. "5" */
  • 类型检查可以在编译时或运行时进行。这意味着弱类型语言既可以是静态类型的,也可以是动态类型的

  • 例如:JavaScript, C, c++, PHP等。