Static/Dynamic vs Strong/Weak
我看到这些术语在编程中到处都是,我对它们的含义有一个模糊的概念。一个搜索显示,事实上,在整个堆栈溢出中都有这样的问题。据我所知,语言中的静态/动态类型与强/弱类型有细微的不同,但我无法理解这种不同。不同的来源似乎使用不同的含义,甚至可以互换使用这些术语。我找不到一个既能说明两者又能说明两者区别的地方。如果有人能在这里为我和世界其他地方把这句话讲清楚,那就好了。
静态/动态类型是关于何时获取类型信息(在编译时或运行时)
强/弱类型是关于类型的区分有多严格(例如,语言是否尝试进行从字符串到数字的隐式转换)。
有关详细信息,请参阅wiki页面。
你在业余爱好者用来谈论编程语言的术语中发现了一个软点。不要使用"强"和"弱"这两个词,因为它们在技术上没有一个普遍认同的含义。相比之下,静态类型意味着程序在执行之前会被检查,并且程序在启动之前可能会被拒绝。动态类型化意味着在执行期间检查值的类型,而类型化不好的操作可能导致程序停止,或者在运行时发出错误信号。静态类型的一个主要原因是排除可能有这样的"动态类型错误"的程序。
强类型通常意味着类型系统中没有漏洞,而弱类型则意味着类型系统可以被破坏(使任何保证无效)。这些术语通常被错误地用于表示静态和动态类型。要了解区别,可以考虑C:语言是在编译时进行类型检查的(静态类型),但是有很多漏洞;您几乎可以将任何类型的值强制转换为其他相同大小的类型,特别是可以自由转换指针类型。Pascal是一种旨在强类型化的语言,但众所周知,它有一个无法预见的漏洞:一个没有标签的变体记录。
强类型语言的实现通常会随着时间的推移而获得漏洞,因此运行时系统的一部分可以用高级语言实现。例如,目标caml有一个名为
说了这句话,你不能指望任何两个人用"强"和"弱"这两个词的方式完全一样。所以避开他们。
简单地说:在静态类型语言中,类型是静态的,这意味着一旦将变量设置为类型,就不能更改它。这是因为类型与变量相关,而不是它所引用的值。
例如在Java中:
1 2 | String str ="Hello"; //statically typed as string str = 5; //would throw an error since java is statically typed |
而在动态类型语言中,类型是动态的,这意味着在将变量设置为类型之后,可以更改它。这是因为键入与值而不是变量相关联。
例如,在python中:
1 2 | str ="Hello" # it is a string str = 5 # now it is an integer; perfectly OK |
另一方面,语言中的强/弱类型与隐式类型转换相关(部分取自@dario的答案):
例如,在python中:
1 2 | str = 5 +"hello" # would throw an error since it does not want to cast one type to the other implicitly. |
而在PHP中:
1 2 | $str = 5 +"hello"; // equals 5 because"hello" is implicitly casted to 0 // PHP is weakly typed, thus is a very forgiving language. |
静态类型允许在编译时检查类型的正确性。通常编译静态类型语言,并解释动态类型语言。因此,动态类型语言可以在运行时检查类型。
弱类型意味着对象的类型可以根据上下文进行更改。例如,在弱类型语言中,如果向字符串"123"中添加另一个数字,则可以将其视为数字123。弱类型语言的例子有bash、awk和php。
另一种弱类型语言是C,在这里内存地址的数据可以通过强制转换被视为不同的类型。
在强类型语言中,对象的类型不会更改-int始终是int,尝试将其用作字符串将导致错误。Java和Python都是强类型的。
动态类型和静态类型的区别在于强制执行类型规则的时候。在静态类型语言中,每个变量和参数的类型必须在源代码中声明,并在编译时强制执行。在动态类型语言中,只有在运行时使用类型时才检查这些类型。因此Java是静态类型的,Python是动态类型化的。
然而,有时边界可能有点模糊。例如,尽管Java是静态类型的,但是每次使用反射或强制转换(例如,当使用对象容器时),都会将类型检查推迟到运行时。
类似地,大多数强类型语言仍然会自动在整数和浮点数之间进行转换(在某些语言中,还有一种非纯精度bigints)。
今天,我在研究这个主题时,看到了这篇伟大的文章:http://blogs.perl.org/users/ovid/2010/08/what-to-know-before-debating-type-systems.html。它为我澄清了很多事情,我认为这可能会增加上面一些伟大的答案。
强和弱类型:
Probably the most common way type systems are classified is"strong"
or"weak." This is unfortunate, since these words have nearly no
meaning at all. It is, to a limited extent, possible to compare two
languages with very similar type systems, and designate one as having
the stronger of those two systems. Beyond that, the words mean nothing
at all.
静态和动态类型
This is very nearly the only common classification of type systems
that has real meaning. As a matter of fact, it's significance is
frequently under-estimated [...] Dynamic and static type systems are
two completely different things, whose goals happen to partially
overlap.A static type system is a mechanism by which a compiler examines
source code and assigns labels (called"types") to pieces of the
syntax, and then uses them to infer something about the program's
behavior. A dynamic type system is a mechanism by which a compiler
generates code to keep track of the sort of data (coincidentally, also
called its"type") used by the program. The use of the same word
"type" in each of these two systems is, of course, not really entirely
coincidental; yet it is best understood as having a sort of weak
historical significance. Great confusion results from trying to find a
world view in which"type" really means the same thing in both
systems. It doesn't.
显式/隐式类型:
When these terms are used, they refer to the extent to which a
compiler will reason about the static types of parts of a program. All
programming languages have some form of reasoning about types. Some
have more than others. ML and Haskell have implicit types, in that no
(or very few, depending on the language and extensions in use) type
declarations are needed. Java and Ada have very explicit types, and
one is constantly declaring the types of things. All of the above have
(relatively, compared to C and C++, for example) strong static type
systems.
从斯科特的编程语言语用学,第3版第291页,我们有
Type checking is the process of ensuring that a program obeys the
language’s type compatibility rules. A violation of the rules is known
as a type clash. A language is said to be strongly typed if it
prohibits, in a way that the language implementation can enforce, the
application of any operation to any object that is not intended to
support that operation. A language is said to be statically typed if
it is strongly typed and type checking can be performed at compile
time. In the strictest sense of the term, few languages are statically
typed. In practice, the termis often applied to languages in which
most type checking can be performed at compile time, and the rest can
be performed at run time.A few examples: Ada is strongly typed, and for the most part
statically typed (certain type constraints must be checked at run
time). A Pascal implementation can also do most of its type checking
at compile time, though the language is not quite strongly typed:
untagged variant records (to be discussed in Section 7.3.4) are its
only loophole. C89 is significantly more strongly typed than its
predecessor dialects, but still significantly less strongly typed than
Pascal. Its loopholes include unions, subroutineswith variable numbers
of parameters, and the interoperability of pointers and arrays (to be
discussed in Section 7.7.1). Implementations of C rarely check
anything at run time.Dynamic (run-time) type checking is a form of late binding, and tends
to be found in languages that delay other issues until run time as
well. Lisp and Smalltalk are dynamically (though strongly) typed. Most
scripting languages are also dynamically typed; some (e.g., Python and
Ruby) are strongly typed. Languages with dynamic scoping are generally
dynamically typed (or not typed at all): if the compiler can’t
identify the object to which a name refers, it usually can’t determine
the type of the object either.
所以简单来说,静态/动态类型化是指类型检查发生的时间:静态类型化的编译时间,动态语言的运行时间。同样,强/弱类型是指语言在执行其类型系统时的攻击性。
我试着把斯科特的描述翻译成一个很好的图表,我在下面发布了。
我认为其他同事做得很好,特别是解释静态和动态类型之间的区别。但就强和弱类型而言,应该说不同的理解/观点。
这里有两个例子:
有人说haskell是强类型的,因为不允许进行任何类型转换。
其他人(例如达里奥的观点)说,一种允许有意从字符串隐式转换为数字的语言是弱类型的,但甚至其他人都称之为"duck-typing"。
这两种说法并没有突出显示类型系统的相反极端,而是完全不同的方面。所以我同意拉姆齐先生的观点,不要用"强"和"弱"来区分类型系统。
静态V/S动态类型语言
- 静态类型语言是在编译时进行类型检查的语言,因此这也意味着在静态类型语言中,每个变量都有一个类型,并且在整个过程中不会改变。与此相反,动态类型语言是在运行时进行类型检查的语言,在编译时不进行类型检查,因此这也意味着在动态类型语言中,可能存在或不存在与变量关联的类型,如果类型关联,则它可以是像JS中的"var"这样的通用类型,其中h对字符串和数字都有好处。
- "动态类型检查语言的实现通常将每个运行时对象与包含其类型信息的类型标记(即对类型的引用)相关联。这种运行时类型信息(rtti)还可以用于实现动态调度、后期绑定、向下强制转换、反射和类似功能。"
- 即使语言是静态类型的,它仍然可以有一些动态类型的特性,这基本上意味着在运行时进行某种类型检查。这在类型转换中很有用。
- 许多有用的和常见的编程语言功能不能静态地检查,例如向下强制转换。因此,许多语言都会同时进行静态和动态类型检查;静态类型检查会验证它能做什么,动态检查会验证其余的。"
- "有些语言允许编写不安全类型的代码。例如,在C语言中,程序员可以在任意两个大小相同的类型之间自由地转换一个值。"
- "静态"类型语言的优点是:
- 因为大多数类型检查是在编译时完成的,所以解释器或运行时可以全速运行,而不必担心类型。
- 由于大多数类型检查都是在编译时完成的,因此它会导致较少的运行时异常或与类型相关的错误。
- "动态"类型化语言的优点是:
- 它们可以帮助实现极快的原型设计,因为开发人员不需要了解类型系统,这样开发人员就可以松散地创建变量并运行它,这就导致了极快的原型设计。
- 静态和动态类型语言列表:
- 静态地:
- 爪哇
- C是静态类型的语言,但与Java相比,"强"类型较小,因为它允许更多隐式转换。
- C++
- C.*
- 动态地:
- 珀尔
- PHP
- Python
- JavaScript
- 红宝石
- 静态地:
- 类型检查是一个重要的安全特性。假设没有类型检查,并且一个方法接受一个名为"creditaccount(bankaccountdetails)"的方法为"bankaccount"的"bankaccount"类型的对象,那么在运行时如果没有类型检查,那么我可以传递一个与"creditaccount(bankaccountdetails)"方法相同的类的对象,并且考虑到我们讨论的是面向对象语言,因为OOP支持"多态性",这里我们讨论的只是"多态性"。因此,基本上,一种面向对象的语言(基本上意味着它支持"多态性")如果没有强类型检查,就可能导致安全问题。
强V/S弱类型语言
- 强类型语言是指在精度损失的情况下不允许隐式转换的语言。例如,在Java中,可以将"int长"转换为"精度",因为不存在精度损失,但不能"隐式"转换为"长到int",因为将丢失精度。相反,在弱类型语言中,即使精度降低,也允许隐式转换。
- 我认为动态类型语言也可以是强类型语言,如果"在运行时"它不允许隐式转换,在这种转换中会失去精度。
良好的进一步阅读
- Type系统
- 强弱打字
- 类别:静态类型的编程语言
- 类别:动态类型编程语言
静态类型语言通常要求您声明变量的类型,然后在编译时检查这些类型以减少错误。"静态类型"中的"静态"一词是指"静态代码分析",即在执行代码之前检查代码的过程。尽管静态类型语言可以从表达式的右侧或实际参数推断变量的类型,但实际上大多数静态类型语言都要求显式声明变量类型。
动态类型语言通常不要求变量声明具有类型,它们根据计算每个赋值语句右侧或函数调用的实际参数时计算的类型推断变量类型。由于变量在其生命周期内可以被赋予多个赋值,因此它的类型可以随着时间而改变,这就是为什么它被称为"动态类型"。此外,运行时环境需要跟踪每个变量的当前类型,因此类型绑定到值,而不是使用变量声明。这可以被视为运行时类型信息(RTTI)系统。
静态和动态类型语言的元素可以组合在一起。例如,C支持静态和动态类型变量,而面向对象语言通常支持向下转换类型层次结构。静态类型语言通常提供各种绕过类型检查的方法,例如使用强制转换、反射和动态调用。
强类型与弱类型是指语言在使用一个变量时,如果它是一种类型,而实际上是另一种类型,那么它会在多大程度上试图防止错误的连续性。例如,C和Java都是静态类型的语言,但是Java使用比C更强大的类型检查。下面的C代码很高兴编译和运行,并且在运行时将变量值放入变量B中,很可能导致bug:
1 2 | char *a ="123"; int b = (int)a; |
等效Java代码将产生编译错误,这通常是优选的:
1 2 | String a ="123" int b = (int)a; |
我最近写了一篇文章解释了这个确切的主题:
https://dev.to/jigh/type-systems-dynamic-vs-static-strong-vs-weak-b6c