Rac*_*hel 894 computer-science programming-languages static-typing dynamic-typing
我听到很多新的编程语言都是动态输入的,但是当我们说一种语言是动态类型而非静态类型时,它实际意味着什么呢?
Nom*_*meN 810
如果在编译时已知变量的类型,则静态键入语言.对于某些语言,这意味着您作为程序员必须指定每个变量的类型(例如:Java,C,C++); 其他语言提供某种形式的类型推断,类型系统推断变量类型的能力(例如:OCaml,Haskell,Scala,Kotlin)
这里的主要优点是所有类型的检查都可以由编译器完成,因此很早就会发现许多琐碎的错误.
示例:C,C++,Java,Rust,Go,Scala
如果类型与运行时值相关联,则动态类型化语言,而不是命名变量/字段/等.这意味着您作为程序员可以更快地编写,因为您不必每次都指定类型(除非使用带有类型推断的静态类型语言).
示例:Perl,Ruby,Python,PHP,JavaScript
大多数脚本语言都具有此功能,因为无论如何都没有编译器进行静态类型检查,但您可能会发现自己正在搜索由于解释器误解变量类型而导致的错误.幸运的是,脚本往往很小,所以bug没有那么多地方可以隐藏.
大多数动态类型语言都允许您提供类型信息,但不需要它.目前正在开发的一种语言Rascal采用混合方法,允许在函数内动态键入,但强制执行函数签名的静态类型.
Chr*_*kar 368
静态类型编程语言在编译时进行类型检查(即验证和强制执行类型约束的过程),而不是运行时.
动态类型编程语言在运行时进行类型检查,而不是编译时.
Aka*_*all 295
下面是一个示例,对比Python(动态类型)和Go(静态类型)如何处理类型错误:
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
Run Code Online (Sandbox Code Playgroud)
Python在运行时进行类型检查,因此:
silly(2)
Run Code Online (Sandbox Code Playgroud)
运行完美,并产生预期的输出Hi
.只有在遇到有问题的行时才会引发错误:
silly(-1)
Run Code Online (Sandbox Code Playgroud)
产生
Run Code Online (Sandbox Code Playgroud)TypeError: unsupported operand type(s) for +: 'int' and 'str'
因为相关的线路实际上已经执行了.
另一方面,在编译时进行类型检查:
package main
import ("fmt"
)
func silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
Run Code Online (Sandbox Code Playgroud)
以上将无法编译,出现以下错误:
Run Code Online (Sandbox Code Playgroud)invalid operation: "3" + 5 (mismatched types string and int)
meh*_*met 153
简单地说就是这样:在静态类型语言中,变量的类型是静态的,这意味着一旦将变量设置为类型,就无法更改它.这是因为键入与变量而不是它所引用的值相关联.
例如在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
Run Code Online (Sandbox Code Playgroud)
另一方面:在动态类型语言中,变量的类型是动态的,这意味着在将变量设置为类型后,您可以更改它.这是因为打字与它所假定的值相关联,而不是与变量本身相关联.
例如在Python中:
str = "Hello" # variable str is linked to a string value
str = 5 # now it is linked to an integer value; perfectly OK
Run Code Online (Sandbox Code Playgroud)
因此,最好将动态类型语言中的变量视为键入值的通用指针.
总而言之,类型描述(或应该描述)语言中的变量而不是语言本身.它可以更好地用作具有静态类型变量的语言,而不是具有动态类型变量 IMHO 的语言.
静态类型语言通常是编译语言,因此,编译器检查类型(完美正确吗?因为类型不允许稍后在运行时更改).
通常会解释动态类型语言,因此在使用它们时会在运行时进行类型检查(如果有).这当然会带来一些性能成本,并且是动态语言(例如,python,ruby,php)不能像键入的那些(java,c#等)那样扩展的原因之一.从另一个角度来看,静态类型语言具有更多的启动成本:使您通常编写更多代码,更难编写代码.但是后来付出了代价.
好处是双方都在借用另一方的特征.类型化语言包含更多动态特性,例如c#中的泛型和动态库,动态语言包括更多类型检查,例如python中的类型注释,或PHP的HACK变体,它们通常不是语言的核心,可用于需求.
在技术选择方面,任何一方都没有内在优势.您是想要更多控制开始还是灵活性,这只是一个偏好问题.只需为工作挑选合适的工具,并确保在考虑开关之前检查相反的可用工具.
Jac*_*cob 38
http://en.wikipedia.org/wiki/Type_system
静态打字
当在编译时执行类型检查而不是运行时,编程语言被称为使用静态类型.在静态类型中,类型与变量而不是值相关联.静态类型语言包括Ada,C,C++,C#,JADE,Java,Fortran,Haskell,ML,Pascal,Perl(关于区分标量,数组,散列和子例程)和Scala.静态类型是一种有限的程序验证形式(参见类型安全性):因此,它允许在开发周期的早期捕获许多类型错误.静态类型检查器仅评估可在编译时确定的类型信息,但能够验证检查的条件是否适用于程序的所有可能执行,这消除了每次执行程序时重复类型检查的需要.通过省略运行时类型检查并启用其他优化,程序执行也可以更有效(即更快或减少内存).
因为它们在编译期间评估类型信息,因此缺少仅在运行时可用的类型信息,所以静态类型检查器是保守的.他们会拒绝一些在运行时可能表现良好的程序,但这些程序无法通过静态确定为良好类型.例如,即使表达式在运行时始终求值为true,也包含代码的程序
Run Code Online (Sandbox Code Playgroud)if <complex test> then 42 else <type error>
因为静态分析无法确定不会采取其他分支,因此将被拒绝为错误类型.[1] 当不经常评估错误时,静态类型检查器的保守行为是有利的:静态类型检查器可以检测很少使用的代码路径中的类型错误.如果没有静态类型检查,即使具有100%代码覆盖率的代码覆盖率测试也可能无法找到此类型错误.代码覆盖率测试可能无法检测到此类型错误,因为必须考虑创建值的所有位置和使用特定值的所有位置的组合.
最广泛使用的静态类型语言不是正式类型安全的.它们在编程语言规范中存在"漏洞",使程序员能够编写绕过静态类型检查器执行的验证的代码,从而解决更广泛的问题.例如,Java和大多数C风格的语言都有类型惩罚,而Haskell具有unsafePerformIO等功能:这样的操作在运行时可能不安全,因为它们会在程序运行时由于错误输入值而导致不必要的行为.
动态打字
当编程语言的大部分类型检查在运行时执行而不是在编译时执行时,编程语言被称为动态类型,或者只是"动态".在动态类型中,类型与值而不是变量相关联.动态类型语言包括Groovy,JavaScript,Lisp,Lua,Objective-C,Perl(关于用户定义类型但不是内置类型),PHP,Prolog,Python,Ruby,Smalltalk和Tcl.与静态类型相比,动态类型可以更灵活(例如,通过允许程序基于运行时数据生成类型和功能),但代价是先验保证较少.这是因为动态类型语言接受并尝试执行某些程序,这些程序可能被静态类型检查器判定为无效.
动态类型可能会导致运行时类型错误 - 也就是说,在运行时,值可能具有意外类型,并且应用了对该类型无意义的操作.这种操作可能在编程错误发生的地方很久之后发生 - 也就是说,错误类型的数据传递到它不应该具有的地方的地方.这使得很难找到bug.
动态类型语言系统与其静态类型的同类相比,对源代码进行的"编译时"检查更少(但会检查,例如,程序在语法上是否正确).运行时检查可能更复杂,因为它们可以使用动态信息以及编译期间出现的任何信息.另一方面,运行时检查仅断言条件在程序的特定执行中保持,并且对于程序的每次执行都重复这些检查.
动态类型语言的开发通常由单元测试等编程实践支持.测试是专业软件开发中的关键实践,在动态类型语言中尤为重要.在实践中,为确保正确的程序操作而进行的测试可以检测比静态类型检查更广泛的错误,但相反地,不能全面地搜索测试和静态类型检查能够检测到的错误.测试可以合并到软件构建周期中,在这种情况下,它可以被认为是"编译时"检查,因为程序用户不必手动运行这样的测试.
参考
- 皮尔斯,本杰明(2002年).类型和编程语言.MIT出版社.国际标准书号0-262-16209-1.
rig*_*old 14
不幸的是,术语"动态类型"具有误导性.所有语言都是静态类型的,类型是表达式的属性(不像某些人认为的那样是值).但是,某些语言只有一种类型.这些被称为单类型语言.这种语言的一个例子是无类型的lambda演算.
在无类型lambda演算中,所有术语都是lambda术语,并且可以对术语执行的唯一操作是将其应用于另一个术语.因此,所有操作总是导致无限递归或lambda术语,但从不发出错误信号.
然而,如果我们用原始数和算术运算来扩充无类型lambda演算,那么我们可以执行无意义的操作,例如将两个lambda项加在一起:(?x.x) + (?y.y)
.有人可能会争辩说,唯一明智的做法就是在发生这种情况时发出错误信号,但为了能够做到这一点,每个值都必须用一个指示符来标记,该指示符指示该术语是lambda术语还是数字.然后,加法运算符将检查两个参数是否都被标记为数字,如果不是,则表示错误.请注意,这些标记不是类型,因为类型是程序的属性,而不是这些程序生成的值.
执行此操作的单类型语言称为动态类型.
JavaScript,Python和Ruby等语言都是单类型的.同样,typeof
JavaScript中的运算符和type
Python中的函数具有误导性的名称; 它们返回与操作数关联的标记,而不是它们的类型.同样,dynamic_cast
在C++和instanceof
Java中也不进行类型检查.
deb*_*yan 13
在编程中,数据类型是一种分类,它告诉我们 1) 变量将保存什么类型的值,2) 可以对这些值执行哪些数学、关系和逻辑运算而不会出错。
当人们在以下上下文中提到“类型”时,他们的意思是“数据类型”。
在每种编程语言中,为了最大限度地减少出现错误的机会,都会在程序执行之前或期间进行类型检查。根据类型检查的时机,有两种类型的编程语言:静态类型和动态类型语言(或混合语言,用户指定每个变量使用哪种(静态/动态))。
此外,根据是否发生隐式类型转换,有两种类型的编程语言:强类型语言和弱类型语言。
类型检查在编译时完成
在源代码中,在变量声明时(将值分配给新变量时),必须显式指定该变量的数据类型(即不能是隐式/推断/猜测的),因为如果数据类型在源代码中指定,然后在编译时源代码将转换为机器代码并允许进行类型检查
这里,数据类型与变量(变量名,而不是值)相关联,例如,int count
。该关联是静态的(固定的)
如果我们尝试通过向已声明的变量 ( int count
) 分配不同数据类型 ( ) 的值来更改int count = "Hello"
其数据类型,则会收到错误
如果我们尝试通过int count
使用不同的数据类型 ( ) 重新声明已声明的变量 ( boolean 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
Run Code Online (Sandbox Code Playgroud)
由于类型检查和类型错误检测是在编译时完成的,因此在运行时不需要进一步的类型检查。因此,程序变得更加优化,执行速度更快
如果我们想要更多类型严格的代码,那么选择这种类型的语言是更好的选择
示例:Java、C、C++、Go、Swift 等。
类型检查在运行时完成
在源代码中,在声明变量时,不需要显式指定该变量的数据类型。由于类型检查是在运行时完成的,因此语言系统根据该变量分配值的数据类型确定变量类型
这里,数据类型与分配给变量的值相关联。例如,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
Run Code Online (Sandbox Code Playgroud)
由于类型检查和类型错误检测是在运行时完成的,动态类型程序的优化程度较低,导致执行速度较慢。尽管这些类型的语言如果实现 JIT(即时)编译器,执行速度会更快
如果我们想轻松地编写和执行代码,那么这种类型的语言是更好的选择,但在这里我们仍然会不幸地得到运行时错误
示例:Python、JavaScript、PHP、Ruby 等。
"当源代码被翻译时"
"检查类型时"
5 + '3'
是强类型语言(如Go和Python)中类型错误的一个示例,因为它们不允许"类型强制" - >值在某些上下文中更改类型的能力,例如合并两种类型.弱类型语言(如JavaScript)不会引发类型错误(导致'53'
).
"静态与编译"和"动态与解释"的定义非常相似......但请记住"当检查类型时"与"源代码翻译时".
无论语言是编译还是解释,您都会得到相同的类型错误!您需要在概念上分离这些术语.
动态,解释
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
silly(2)
Run Code Online (Sandbox Code Playgroud)
因为Python既被解释又被动态地键入,它只对它正在执行的代码进行转换和类型检查.该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)
}
Run Code Online (Sandbox Code Playgroud)
在运行之前检查类型(静态)并立即捕获类型错误!如果解释了类型,则在运行时仍会检查这些类型,结果相同.如果它是动态的,即使在编译期间查看代码,它也不会抛出任何错误.
如果编译语言是静态类型(动态对比),则它在运行时会有更好的性能; 类型知识允许机器代码优化.
由于不需要在执行时动态检查类型(它在运行之前检查),因此静态类型语言在运行时本质上具有更好的性能.
类似地,编译语言在运行时更快,因为代码已经被翻译而不是需要动态地"解释"/翻译它.
请注意,编译和静态类型语言在运行转换和类型检查之前都会有延迟.
静态类型提前捕获错误,而不是在执行期间找到它们(对于长程序尤其有用).它更加"严格",因为它不会在程序中的任何地方出现类型错误,并且通常会阻止变量更改类型,从而进一步防止意外错误.
num = 2
num = '3' // ERROR
Run Code Online (Sandbox Code Playgroud)
动态类型更灵活,有些人欣赏.它通常允许变量更改类型,这可能导致意外错误.
静态类型语言:每个变量和表达式在编译时都是已知的。
(int a;
a在运行时只能接受整数类型值)
示例:C,C ++,Java
动态类型语言:变量在运行时可以接收不同的值,并且它们的类型在运行时定义。
(var a;
a在运行时可以采用任何类型的值)
示例:Ruby,Python。