关于静态类型:静态类型和动态类型语言有什么区别?

What is the difference between statically typed and dynamically typed languages?

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


statically型语言

a语言是statically型如果A变量类型在编译时是已知的。这意味着,你的一些语言为程序员必须指定每个变量的类型是什么(例如:Java,C,C++);其他语言提供一些形式的推理类型,类型系统deduce能力变量的类型(例如:OCaml,Haskell,Scala,kotlin)

主要优势在这里是做各种检查可以由编译器,因此很多琐碎的错误是夹在一个非常早期的阶段。

例子:C,C++,Java,锈,CRP,Scala

dynamically型语言

如果语言是dynamically型A型是与运行时的值,变量和不命名/机场/等。这意味着你作为一个程序员可以写一小,因为你越没有指定类型的每一次(除非使用一个statically型语言类型的推理)。

例子:Perl,Python,Ruby,PHP,JavaScript

大多数脚本语言有没有这个特征做为编译器的静态类型检查,但你可以找到你自己,寻找一个解释器错误这是由于misinterpreting A类型的变量。一个小的脚本错误,所以没有太多的地方隐藏。

让你做最dynamically型语言提供的信息类型,但不需要它。这是一个正在开发的语言,需要一个混合的方法中的流氓之间的动态和静态打字打字功能,但执行的函数签名。


statically型编程语言做类型检查(IU的过程核查和执行的约束(类型)为反对在编译时和运行时。

dynamically型编程语言的运行时类型检查的任务在一个反对的编译时。


这是在对比的例子(dynamically Python知识型)和CRP(statically型型错误:a)手柄

1
2
3
4
5
def silly(a):
    if a > 0:
        print 'Hi'
    else:
        print 5 + '3'

Python是在运行时类型检查,因此:

1
silly(2)

运行非常精细,和预期的输出Hi副车架。如果错误仍然是唯一的problematic是打线:

1
silly(-1)

副车架

1
TypeError: unsupported operand type(s) for +: 'int' and 'str'

什么是执行,因为相关的线。

在其他的手去做:在编译时类型检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import ("fmt"
)

func silly(a int) {
    if (a > 0) {
        fmt.Println("Hi")
    } else {
        fmt.Println("3" + 5)
    }
}

func main() {
    silly(2)
}

上述不编译,与下面的错误:

1
invalid operation:"3" + 5 (mismatched types string and int)


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

例如在Java中:

1
2
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中:

1
2
str ="Hello" # variable str is linked to a string value
str = 5       # now it is linked to an integer value; perfectly OK

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

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

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

动态类型语言通常是被解释的,因此当使用它们时,类型检查(如果有的话)在运行时发生。这当然会带来一些性能成本,这也是动态语言(例如,Python、Ruby、PHP)没有按类型化(Java、C等)的原因之一。从另一个角度来看,静态类型语言有更多的启动成本:通常会使您编写更多的代码,更难的代码。但这会在以后得到回报。

好消息是,双方都在从另一方借用特性。类型化语言包含了更多的动态特性,例如C中的泛型和动态库,动态语言包含了更多的类型检查,例如,python中的类型注释,或者php的hack变体,它们通常不是语言的核心,可以根据需要使用。

在技术选择上,双方都没有内在的优势。不管你是想要更多的控制权还是灵活性,这只是一个偏好问题。只需为工作选择合适的工具,并确保在考虑切换之前,从相反的角度检查可用的工具。


http:///wiki/_产生式系统

Static typing

A programming language is said to use
static typing when type checking is
performed during compile-time as
opposed to run-time. In static typing,
types are associated with variables
not values. Statically typed languages
include Ada, C, C++, C#, JADE, Java,
Fortran, Haskell, ML, Pascal, Perl
(with respect to distinguishing
scalars, arrays, hashes and
subroutines) and Scala. Static typing
is a limited form of program
verification (see type safety):
accordingly, it allows many type
errors to be caught early in the
development cycle. Static type
checkers evaluate only the type
information that can be determined at
compile time, but are able to verify
that the checked conditions hold for
all possible executions of the
program, which eliminates the need to
repeat type checks every time the
program is executed. Program execution
may also be made more efficient (i.e.
faster or taking reduced memory) by
omitting runtime type checks and
enabling other optimizations.

Because they evaluate type information
during compilation, and therefore lack
type information that is only
available at run-time, static type
checkers are conservative. They will
reject some programs that may be
well-behaved at run-time, but that
cannot be statically determined to be
well-typed. For example, even if an
expression always
evaluates to true at run-time, a
program containing the code

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

will be rejected as ill-typed, because
a static analysis cannot determine
that the else branch won't be
taken.[1] The conservative behaviour
of static type checkers is
advantageous when
evaluates to false infrequently: A
static type checker can detect type
errors in rarely used code paths.
Without static type checking, even
code coverage tests with 100% code
coverage may be unable to find such
type errors. Code coverage tests may
fail to detect such type errors
because the combination of all places
where values are created and all
places where a certain value is used
must be taken into account.

The most widely used statically typed
languages are not formally type safe.
They have"loopholes" in the
programming language specification
enabling programmers to write code
that circumvents the verification
performed by a static type checker and
so address a wider range of problems.
For example, Java and most C-style
languages have type punning, and
Haskell has such features as
unsafePerformIO: such operations may
be unsafe at runtime, in that they can
cause unwanted behaviour due to
incorrect typing of values when the
program runs.

Dynamic typing

A programming language is said to be
dynamically typed, or just 'dynamic',
when the majority of its type checking
is performed at run-time as opposed to
at compile-time. In dynamic typing,
types are associated with values not
variables. Dynamically typed languages
include Groovy, JavaScript, Lisp, Lua,
Objective-C, Perl (with respect to
user-defined types but not built-in
types), PHP, Prolog, Python, Ruby,
Smalltalk and Tcl. Compared to static
typing, dynamic typing can be more
flexible (e.g. by allowing programs to
generate types and functionality based
on run-time data), though at the
expense of fewer a priori guarantees.
This is because a dynamically typed
language accepts and attempts to
execute some programs which may be
ruled as invalid by a static type
checker.

Dynamic typing may result in runtime
type errors—that is, at runtime, a
value may have an unexpected type, and
an operation nonsensical for that type
is applied. This operation may occur
long after the place where the
programming mistake was made—that is,
the place where the wrong type of data
passed into a place it should not
have. This makes the bug difficult to
locate.

Dynamically typed language systems,
compared to their statically typed
cousins, make fewer"compile-time"
checks on the source code (but will
check, for example, that the program
is syntactically correct). Run-time
checks can potentially be more
sophisticated, since they can use
dynamic information as well as any
information that was present during
compilation. On the other hand,
runtime checks only assert that
conditions hold in a particular
execution of the program, and these
checks are repeated for every
execution of the program.

Development in dynamically typed
languages is often supported by
programming practices such as unit
testing. Testing is a key practice in
professional software development, and
is particularly important in
dynamically typed languages. In
practice, the testing done to ensure
correct program operation can detect a
much wider range of errors than static
type-checking, but conversely cannot
search as comprehensively for the
errors that both testing and static
type checking are able to detect.
Testing can be incorporated into the
software build cycle, in which case it
can be thought of as a"compile-time"
check, in that the program user will
not have to manually run such tests.

References

  • Pierce, Benjamin (2002). Types and Programming Languages. MIT Press.
    ISBN 0-262-16209-1.

  • 不幸的是,"动态类型化"这一术语具有误导性。所有语言都是静态类型的,类型是表达式的属性(不是一些人认为的值)。但是,有些语言只有一种类型。这些被称为单类型语言。这种语言的一个例子是非类型化lambda微积分。

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

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

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

    JavaScript、Python和Ruby等语言都是单类型的。同样,javascript中的typeof操作符和python中的type函数的名称有误导性;它们返回与操作数相关的标记,而不是它们的类型。类似地,Java中的EDCOX1 3和EDCOX1 4的引用不做类型检查。


    编译与解释

    "翻译源代码时"

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

    打字

    "检查类型时"

    5 + '3'是强类型语言(如go和python)中类型错误的一个例子,因为它们不允许"类型强制"->值在某些上下文(如合并两个类型)中更改类型的能力。弱类型语言(如javascript)不会引发类型错误(导致'53')。

    • 静态:运行时之前检查的类型
    • 动态:执行期间动态检查的类型

    "static&compiled"和"dynamic&explocated"的定义非常相似……但请记住,"当类型被选中时"和"当源代码被翻译时"。

    不管语言是编译的还是解释的,您都会得到相同的类型错误!您需要从概念上分离这些术语。

    Python示例

    动态,解释

    1
    2
    3
    4
    5
    6
    7
    def silly(a):
        if a > 0:
            print 'Hi'
        else:
            print 5 + '3'

    silly(2)

    因为python既是解释的,也是动态类型的,所以它只转换和类型检查它正在执行的代码。else块从未执行过,所以5 + '3'从未被查看过!

    如果它是静态类型的呢?

    在代码运行之前会引发类型错误。它仍然在运行时之前执行类型检查,即使它被解释了。

    如果它是编译的呢?

    else块将在运行时之前被转换/查看,但因为它是动态类型的,所以不会引发错误!动态类型语言在执行之前不会检查类型,并且该行永远不会执行。

    去例

    静态,已编译

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package main

    import ("fmt"
    )

    func silly(a int) {
      if (a > 0) {
          fmt.Println("Hi")
      } else {
          fmt.Println("3" + 5)
      }
    }

    func main() {
      silly(2)
    }

    运行前检查类型(静态),立即捕获类型错误!如果解释了类型,那么在运行时之前仍然会检查这些类型,结果相同。如果它是动态的,它不会抛出任何错误,即使在编译期间会查看代码。

    性能

    如果编译语言是静态类型的(而不是动态类型),那么它在运行时的性能会更好;类型知识允许机器代码优化。

    静态类型语言本质上在运行时具有更好的性能,因为在执行时不需要动态检查类型(它在运行前进行检查)。

    同样,编译语言在运行时速度更快,因为代码已经被翻译,而不需要"解释"/即时翻译。

    请注意,编译语言和静态类型语言在分别运行翻译和类型检查之前都会有延迟。

    更多差异

    静态类型会在执行期间尽早捕获错误,而不是查找错误(对于长程序尤其有用)。它更加"严格",因为它不允许在程序中的任何地方出现类型错误,并且经常阻止变量更改类型,从而进一步防止意外错误。

    1
    2
    num = 2
    num = '3' // ERROR

    动态打字更灵活,有些人很欣赏。它通常允许变量更改类型,这可能导致意外错误。


    静态类型语言在编译时进行类型检查,类型不能更改。(不要使用类型转换注释,会创建一个新的变量/引用)。

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


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

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

    实例:C、C++、Java

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

    (var a;a可以在运行时获取任何类型的值)

    示例:ruby、python。


    简单明了的定义,但符合需求:静态类型语言将类型绑定到其整个范围内的变量(seg:scala)动态类型语言将类型绑定到变量引用的实际值。


    • 在静态类型语言中,变量与编译时已知的类型相关联,并且该类型在程序执行期间保持不变。同样,只能为变量分配一个值,该值是已知/指定类型的实例。
    • 在动态类型语言中,变量没有类型,并且它在执行期间的值可以是任何形状和形式的任何东西。


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

    而且,它们之间的差异非常小,可以与强类型和弱类型语言联系在一起。强类型语言不允许您使用另一种类型,如E.C和C++。而弱类型语言允许EG.Python。


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


    静态表征:《Java与Scala语言如是静态型。

    变量的定义和initialized之前一定要把你的代码中使用。

    for(int x,x = 10。;;;;;;;;

    System.out.println(x);

    动态表征:Perl语言是动态类型的。

    变量需要被保存initialized之前,他们是用代码。

    使用这个变量y = 10;在以后的部分代码