当我们说一种语言是动态类型语言还是静态类型语言时,这意味着什么?
当我们说一种语言是动态类型语言还是静态类型语言时,这意味着什么?
如果变量的类型在编译时已知,则该语言为静态类型。对于某些语言,这意味着作为程序员的您必须指定每个变量的类型;其他语言(例如:Java、C、C++)提供某种形式的类型推断,即类型系统能够推断变量的类型(例如:OCaml、Haskell、Scala、Kotlin)。
主要优点在于编译器可以进行各种检查,因此很多琐碎的错误都可以在非常早期被捕获。
示例:C、C++、Java、Rust、Go、Scala
如果类型与运行时值相关联,而不是命名的变量/字段等,则该语言为动态类型。这意味着作为程序员,您可以写得更快,因为您不必每次都指定类型(除非使用具有类型推断的静态类型语言)。
示例:Perl、Ruby、Python、PHP、JavaScript、Erlang
大多数脚本语言都具有此功能,因为没有编译器进行静态类型检查,但您可能会发现自己在寻找由解释器错误解释变量类型而导致的错误。幸运的是,脚本通常很小,因此错误没有太多藏身之处。
大多数动态类型语言允许您提供类型信息,但不要求。目前正在开发的Rascal语言采用混合方法,在函数内允许动态类型,但强制执行函数签名的静态类型。类型检查是验证和强制执行类型限制的过程。
静态类型编程语言在 编译时 进行类型检查。
例如:Java,C,C++。
动态类型编程语言在 运行时 进行类型检查。
例如:Perl,Ruby,Python,PHP,JavaScript。
var
关键字,为Java开发者提供了一种 动态类型 的体验,但Java仍然是静态类型 的。 - jumping_monkeyvar
时,你告诉编译器,“请为我推断类型”。程序会被编译成与你写下的特定类型完全相同。当变量使用不正确时,编译器将发出类型错误。动态类型意味着类型仅在运行时(实际上与变量无关)才知道,正如NomeN所指出的那样。当然,这在Java中完全不是这种情况。 - Laar这里有一个例子,对比展示了Python(动态类型语言)和Go(静态类型语言)处理类型错误的方式:
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
Python在运行时进行类型检查,因此:
silly(2)
代码完全正常,输出结果为Hi
。只有当触发出问题的那行代码时才会引发错误:
silly(-1)
产生TypeError: unsupported operand type(s) for +: 'int' and 'str'
因为相关的行实际上被执行了。
另一方面,Go语言在编译时进行类型检查:
package main
import ("fmt"
)
func silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
上述代码无法编译,会出现以下错误: invalid operation: "3" + 5 (mismatched types string and int)
runhaskell
进行解释。 - Joshua Grosso Reinstate CMs简单来说:在静态类型语言中,变量的类型是静态的,这意味着一旦你将一个变量设置为某种类型,就不能更改它。因为类型与变量相关联,而不是与它所引用的值相关联。
例如,在Java中:
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中:
some_str = "Hello" # variable some_str is linked to a string value
some_str = 5 # now it is linked to an integer value; perfectly OK
因此,在动态类型语言中,最好将变量视为指向类型值的通用指针。
总之,类型应该描述(或者说应该描述)语言中的变量,而不是语言本身。在我看来,它可以更好地用作具有静态类型变量的语言与具有动态类型变量的语言之间的区分。
静态类型语言通常是编译型语言,因此编译器会检查类型(很合理对吧?因为类型不能在运行时更改)。
动态类型语言通常是解释型的,因此类型检查(如果有的话)发生在使用时的运行时。当然,这会带来一些性能成本,并且是动态语言(例如Python、Ruby、PHP)不如静态语言(Java、C#等)扩展良好的原因之一。从另一个角度来看,静态类型语言有更多的启动成本:通常需要编写更多、更难的代码。但这会带来回报。
好消息是,两边都在互相借鉴特性。类型化语言正在整合更多的动态特性,例如C#中的泛型和动态库,而动态语言正在加入更多的类型检查,例如Python中的类型注释,或者PHP的HACK变体,这些通常不是语言的核心部分,可以按需使用。
在技术选择方面,两边都没有固有的优势。这只是一个偏好问题,你是想要更多的控制权还是更多的灵活性。选择适合工作的正确工具,并确保在考虑切换之前检查在相反方面可用的内容。
http://en.wikipedia.org/wiki/Type_system
静态类型
编程语言在编译时执行类型检查而非运行时被称为静态类型。在静态类型中,类型与变量相关联而非值。静态类型语言包括Ada、C、C++、C#、JADE、Java、Fortran、Haskell、ML、Pascal、Perl(区分标量、数组、哈希和子程序)和Scala。静态类型是程序验证的一种有限形式(见类型安全性),因此它允许在开发周期的早期捕获许多类型错误。静态类型检查器只评估可以在编译时确定的类型信息,但能够验证所检查的条件对程序的所有可能执行都成立,这消除了每次执行程序时重复进行类型检查的需要。通过省略运行时类型检查并启用其他优化,程序执行也可以更加高效(即更快或占用更少的内存)。
由于它们在编译过程中评估类型信息,因此缺乏仅在运行时可用的类型信息,静态类型检查器是保守的。它们将拒绝一些可能在运行时表现良好但不能静态确定可以很好地类型化的程序。例如,即使一个表达式在运行时始终评估为true,包含该代码的程序也会被拒绝。
if <complex test> then 42 else <type error>
在运行时,而不是在编译时,因此
只有在程序运行时才会出现类型错误,
当值的类型与操作所要求的类型不匹配时。
这样的错误可能很难发现,因为它们
只能在特定输入或情况下出现。动态类型
检查器不能在编译时捕获这些错误,
但通常会在运行时抛出异常。
与静态类型相比,动态类型可以更加灵活, 因为它允许程序基于运行时数据生成类型和功能, 但这也意味着它提供的保证较少。许多动态类型 语言具有强大的元编程能力,可以修改自身的 行为,这使得它们对于某些问题(例如模板编程) 非常有用。
类型推断
类型推断是一种编程语言特性, 可以在编译时自动推断变量的类型, 而无需人工标注类型信息。类型 推断通常与静态类型检查器一起使用, 因为它可以减轻程序员的负担并提高 代码可读性。常见的支持类型推断的语言包括 C++11、Go、Haskell、Java 8、Kotlin、Rust等。
在程序错误发生的地方之后很久,也就是错误类型的数据传入了不应该传入的位置。这使得错误难以定位。
与静态类型的编程语言相比,动态类型的语言系统对源代码进行较少的“编译时”检查(但会检查程序是否符合语法规范)。运行时检查可能更加复杂,因为它们既可以使用动态信息,也可以使用编译期间存在的任何信息。另一方面,运行时检查只断言在程序特定执行中条件成立,这些检查将在每个程序执行中重复进行。
在动态类型语言中进行开发通常需要借助单元测试等编程实践。测试是专业软件开发的关键实践,在动态类型语言中尤其重要。实际上,为确保程序正确运行所进行的测试可以检测到比静态类型检查更广泛的错误,但反过来,它不能像测试和静态类型检查一样全面地搜索能够检测到的错误。测试可以并入软件构建周期中,在这种情况下,它可以被视为“编译时”检查,因为程序用户不必手动运行此类测试。
参考文献
myObject[remoteDataName]
。那么就无法知道它将选择哪个属性,甚至无法确定它是否是一个有效的属性。 - Mike Cluck当源代码被翻译时……
当类型被检查时……
5 + '3'
是 强类型 语言,如 Go 和 Python 中的类型错误示例,因为它们不允许 "类型强制转换" -> 在某些情况下,值可以改变类型(例如合并两种类型)。弱类型 语言,例如 JavaScript,不会抛出类型错误(结果为 '53'
)。
"静态和编译" 与 "动态和解释" 的定义非常相似……但请记住,这是 "类型被检查时" 与 "源代码被翻译时"的区别。
无论语言是否编译,您将获得相同的类型错误!您需要在概念上分离这些术语。
动态,解释
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
silly(2)
else
块永远不会执行,因此5 + '3'
甚至都没有被考虑过!
如果它是静态类型的呢?
在代码运行之前将会抛出类型错误。尽管它是解释性的,但仍会在运行时之前执行类型检查。
如果它被编译了呢?
else
块将在运行之前被翻译/检查,但由于它是动态类型的,所以不会抛出错误!动态类型语言直到执行时才检查类型,而那一行永远不会执行。
package main
import ("fmt"
)
func silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
在运行之前(静态),类型会进行检查,因此类型错误会立即被捕获!如果是解释型的话,运行时仍然会对类型进行检查,结果相同。如果是动态的,则不会抛出任何错误,即使代码在编译期间被查看也是如此。
如果一个编译语言是静态类型的(与动态类型相比),那么它在运行时将具有更好的性能;类型知识允许进行机器码优化。
由于在执行时无需动态检查类型(它在运行之前检查),所以静态类型的语言本质上具有更好的运行时性能。
同样,编译语言在运行时更快,因为代码已经被翻译,而不需要实时“解释”/翻译它。
请注意,编译和静态类型的语言都需要在运行之前进行翻译和类型检查,因此会有一定的延迟。
静态类型可以提早捕获错误,而不是在执行过程中发现错误(特别适用于长程序)。它更加“严格”,不允许程序中出现任何类型错误,并且通常防止变量改变类型,从而进一步防止意外错误。
num = 2
num = '3' // ERROR
动态类型更加灵活,一些人很欣赏这一点。它通常允许变量改变类型,这可能会导致意外错误。
(λx.x) + (λy.y)
。可以说,唯一明智的做法是在此时发出错误信号,但要能够做到这一点,每个值都必须标记为指示符,指示该项是λ术语还是数字。然后,加法运算符将检查确实两个参数都被标记为数字,如果它们没有,则发出错误信号。请注意,这些标记不是类型,因为类型是程序的属性,而不是由这些程序产生的值的属性。静态类型语言:每个变量和表达式在编译时已知。
(int a;
在运行时a只能取整数类型的值)
例子:C、C++、Java
动态类型语言:变量可以在运行时接收不同的值,并且它们的类型在运行时定义。
(var a;
在运行时a可以取任何类型的值)
例子:Ruby、Python。
类型检查在编译时完成
在源代码中,在变量声明时(即为新变量分配值的时间),必须明确指定该变量的数据类型(即不能是隐式/推断/猜测的),因为如果在源代码中指定了数据类型,则在编译时该源代码将被转换为机器代码并允许进行类型检查
这里,数据类型与变量相关联(变量名而非值),例如 int count
。此关联是静态的(固定的)
如果我们尝试通过将不同数据类型的值(int count = "Hello"
)赋给已声明变量(int count
)来更改已声明变量的数据类型,则会出现错误
如果我们尝试通过使用不同数据类型(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
类型检查在运行时完成
在源代码中,在变量声明时,不需要显式指定该变量的数据类型。因为类型检查是在运行时完成的,语言系统从该变量分配值的数据类型确定变量类型
这里,数据类型与分配给变量的值相关联。例如,var foo = 10
:10 是一个数字,所以现在 foo 是数字数据类型。但这种关联是动态的(灵活的)
我们可以通过将不同数据类型的值(foo = "Hi"
)分配给已经声明的变量(var foo = 10
),而不会产生错误,轻松更改已经声明变量的数据类型
我们可以通过使用其他数据类型的值重新声明它(var foo = true
),而不会产生错误,轻松更改已经声明变量的数据类型(var foo = 10
)
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等。
静态类型语言在编译时进行类型检查,类型不可更改。(不要在类型转换注释中玩花样,会创建一个新的变量/引用)。
动态类型语言在运行时进行类型检查,变量的类型可以在运行时更改。