我看到这些术语在编程中无处不在,我对它们的含义有一个模糊的概念。搜索显示我实际上已经在整个堆栈溢出中询问了此类问题。据我所知,语言中的静态/动态键入与强/弱键入有细微的区别,但是这种差异是我难以理解的。不同的来源似乎使用不同的含义,甚至可以互换使用这些术语。我找不到某个地方可以同时谈论这两者,并能说明差异。最好的是,如果有人可以在这里为我和世界其他地方清楚地说明这一点。
我看到这些术语在编程中无处不在,我对它们的含义有一个模糊的概念。搜索显示我实际上已经在整个堆栈溢出中询问了此类问题。据我所知,语言中的静态/动态键入与强/弱键入有细微的区别,但是这种差异是我难以理解的。不同的来源似乎使用不同的含义,甚至可以互换使用这些术语。我找不到某个地方可以同时谈论这两者,并能说明差异。最好的是,如果有人可以在这里为我和世界其他地方清楚地说明这一点。
Answers:
静态/动态打字为约当类型信息被获取(无论是在编译时或在运行时)
强/弱键入是关于如何严格区分类型(例如,语言是否尝试进行从字符串到数字的隐式转换)。
有关更多详细信息,请参见Wiki页面。
"12" + "34"
因此等于"46"
,但"12" + "34Q"
等于"1234Q"
[幸运的是,"12" & "34"
如果有人想要串联,则可以编写]。奇怪的是,保存数字的变量将它们存储为双精度浮点数,并且此类变量的数学运算使用浮点值而不用字符串修饰,但是无法询问变量是字符串还是数字。
您已经发现业余爱好者用来谈论编程语言的术语上的薄弱之处。 请勿使用“强”和“弱”类型的术语,因为它们在技术含义上尚未达成共识。相比之下,静态类型化意味着在执行程序之前先检查程序,然后在启动程序之前将其拒绝。 动态类型化意味着在执行过程中会检查值的类型,而类型错误的操作可能会导致程序停止运行或在运行时发出错误信号。静态类型化的主要原因是要排除可能具有此类“动态类型错误”的程序。
强类型通常意味着类型系统中没有漏洞,而弱类型意味着类型系统可以被破坏(使任何保证无效)。这些术语经常被错误地使用来表示静态和动态类型。要了解它们之间的区别,请考虑一下C:在编译时对语言进行类型检查(静态类型化),但是存在很多漏洞;您几乎可以将任何类型的值转换为相同大小的另一类型-特别是,您可以自由地转换指针类型。帕斯卡(Pascal)是一种旨在强力打字的语言,但著名的是无法预料的漏洞:没有标签的变体记录。
强类型语言的实现通常会随着时间的流逝而产生漏洞,因此,可以使用高级语言来实现部分运行时系统。例如,Objective Caml有一个称为的函数Obj.magic
,具有仅返回其参数的运行时效果,但是在编译时,它将任何类型的值转换为任何其他类型的值。我最喜欢的示例是Modula-3,其设计者将其称为类型转换构造LOOPHOLE
。
话虽如此,您不能指望任何两个人以完全相同的方式使用“强”和“弱”两个词。所以避免他们。
简单地说就是这样:在静态类型语言中,类型是static,这意味着一旦将变量设置为类型,就无法更改它。那是因为类型是与变量关联的,而不是变量所引用的值。
例如在Java中:
String str = "Hello"; //statically typed as string
str = 5; //would throw an error since java is statically typed
而在动态类型语言中,类型是dynamic,这意味着在将变量设置为类型之后,可以对其进行更改。这是因为键入与值而不是变量相关联。
例如在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.
静态类型允许在编译时检查类型正确性。通常编译静态类型的语言,并解释动态类型的语言。因此,动态类型的语言可以在运行时检查类型。
弱类型意味着对象的类型可以根据上下文而改变。例如,在弱类型语言中,如果在字符串中添加另一个数字,则字符串“ 123”将被视为数字123。bash,awk和PHP是弱类型语言的示例。
另一种弱类型语言是C,可以通过强制转换将内存地址中的数据视为其他类型。
在强类型语言中,对象的类型不会改变-int始终是int,尝试将其用作字符串会导致错误。Java和Python都是强类型的。
动态类型和静态类型之间的区别在于强制执行类型规则的时间。在静态类型语言中,每个变量和参数的类型必须在源代码中声明,并在编译时强制执行。在动态类型语言中,仅在运行时使用类型时才检查类型。因此,Java是静态类型的,而Python是动态类型的。
但是,有时边界可能会有些模糊。例如,尽管Java是静态类型的,但是每次使用反射或强制类型转换(例如,使用对象容器时)时,它们都会将类型检查推迟到运行时。
同样,大多数强类型语言仍将在整数和浮点数之间自动转换(在某些语言中为任意精度BigInts)。
f
接受参数x
(fun f(x)
)[**,所以没有声明任何类型**],函数主体为x+1
。没有声明任何类型,编译器会弄清楚这x
必须是一个int。- fun f x = x + 1;
val f = fn : int -> int
5 + 'c' // OK
今天,研究这个课题我碰到这篇大文章来http://blogs.perl.org/users/ovid/2010/08/what-to-know-before-debating-type-systems.html它清除了很多对我而言,我认为这可能会增加上面的一些出色答案。
强弱键入:
类型系统最常见的分类方式可能是“强”或“弱”。不幸的是,因为这些词几乎没有任何意义。在有限的范围内,可以将两种语言与类型非常相似的系统进行比较,并指定其中一种具有这两种语言中的较强者。除此之外,这些词根本没有任何意义。
静态和动态类型
这几乎是唯一具有真正意义的类型系统的常见分类。实际上,它的重要性经常被低估。动态和静态类型系统是两个完全不同的事物,它们的目标恰巧部分重叠。
静态类型系统是一种机制,编译器通过该机制检查源代码,并为语法的各个部分分配标签(称为“类型”),然后使用它们来推断有关程序行为的信息。动态类型系统是一种机制,通过该机制编译器可以生成代码来跟踪程序使用的数据种类(巧合的是,也称为“类型”)。当然,在这两个系统中的每个词上使用相同的“类型”一词并不是完全偶然的。但最好的理解是,它具有某种薄弱的历史意义。试图找到一种世界观,其中“类型”在两个系统中实际上意味着相同的东西,从而造成极大的混乱。没有。
显式/隐式类型:
使用这些术语时,它们指的是编译器对程序各部分的静态类型进行推理的程度。所有编程语言都有某种形式的类型推理。有些比其他更多。ML和Haskell具有隐式类型,因为不需要(或很少,取决于使用的语言和扩展名)类型声明。Java和Ada具有非常明确的类型,其中一种是不断声明事物的类型。以上所有内容都具有(例如,与C和C ++相比)强大的静态类型系统。
从Scott的《Programming Language Pragmatics》,第3版,第291页,
类型检查是确保程序遵守语言的类型兼容性规则的过程。违反规则称为类型冲突。如果某种语言禁止以某种语言实现可以强制的方式将任何操作应用于不打算支持该操作的任何对象,则该语言被称为强类型。如果语言是强类型的,则称该语言为静态类型,并且可以在编译时执行类型检查。从最严格的意义上讲,很少有语言是静态键入的。在实践中,该术语通常应用于可以在编译时执行大多数类型检查,而其余部分可以在运行时执行的语言。
举几个例子:Ada是强类型的,并且在大多数情况下是静态类型的(必须在运行时检查某些类型的约束)。Pascal实现也可以在编译时进行大多数类型检查,尽管该语言的类型不是很严格:未标记的变体记录(将在第7.3.4节中讨论)是唯一的漏洞。C89的打字强度明显高于其前身方言,但打字强度却远低于Pascal。它的漏洞包括并集,带有可变数量参数的子例程以及指针和数组的互操作性(将在第7.7.1节中讨论)。C的实现很少在运行时检查任何内容。
动态(运行时)类型检查是后期绑定的一种形式,并且倾向于在将其他问题推迟到运行时的语言中找到。Lisp和Smalltalk是动态(尽管很强)类型的。大多数脚本语言也可以动态键入。有些(例如Python和Ruby)是强类型的。具有动态作用域的语言通常是动态键入的(或根本不键入):如果编译器无法识别名称所引用的对象,则通常也无法确定对象的类型。
简单来说,静态/动态类型是指进行类型检查的时间:静态类型的编译时间和动态语言的运行时间。同样,强类型/弱类型是指语言在执行其类型系统时的积极程度。
我试图将Scott的描述翻译成一个漂亮的图表,下面将其发布。
静态类型的语言通常要求您声明变量的类型,然后在编译时对其进行检查以减少错误。“静态类型化”中的“静态”一词是指“静态代码分析”,这是在执行代码之前检查代码的过程。尽管静态类型的语言可以从表达式的右侧或实际参数推断变量的类型,但实际上大多数静态类型的语言都要求显式声明变量类型。
动态类型的语言通常不需要变量声明具有类型,并且它们根据对每个赋值语句的右侧或函数调用的实际参数求值而得出的类型来推断变量类型。由于可以在变量的整个生命周期内对其进行多次分配,因此其类型可以随时间变化,这就是为什么将其称为“动态类型”。另外,运行时环境需要跟踪每个变量的当前类型,因此类型绑定到值,而不是变量声明。可以将其视为运行时类型信息(RTTI)系统。
静态和动态类型语言的元素可以组合。例如,C#支持静态和动态类型变量,而面向对象的语言通常支持向下转换类型层次结构。静态类型的语言通常提供各种方法来绕过类型检查,例如通过使用强制转换,反射和动态调用。
强类型与弱类型是指语言试图防止由于使用变量而导致的错误的连续性,就像实际上是另一种类型一样。例如,C和Java都是静态类型的语言,但是Java比C使用更强的类型检查。以下C代码很乐意编译和运行,并且会在运行时将随机值放入变量b中,很可能导致错误:
char *a = "123";
int b = (int)a;
等效的Java代码将产生编译错误,通常更可取:
String a = "123"
int b = (int)a;