强类型语言和静态类型语言有什么区别?


Answers:


542

强类型语言和静态类型语言有什么区别?

静态类型的语言具有类型系统,该类型系统在实现时由实现(编译器或解释器)检查。类型检查拒绝某些程序,并且通过检查的程序通常带有一些保证。例如,编译器保证不对浮点数使用整数算术指令。

关于“强类型”的含义并没有真正的共识,尽管专业文献中使用最广泛的定义是使用“强类型”语言,但是程序员不可能解决类型系统所施加的限制。 。这个术语几乎总是用来描述静态类型的语言。

静态与动态

静态类型的反义词是“动态类型”,这意味着

  1. 运行时使用的值分为几种类型。
  2. 有关如何使用此类值的限制。
  3. 违反这些限制时,违反将被报告为(动态)类型错误。

例如,Lua是一种动态类型的语言,除其他外,还具有字符串类型,数字类型和布尔类型。在Lua中,每个值都完全属于一个类型,但是这并不适用于所有动态类型语言的要求。在Lua中,允许串联两个字符串,但不允许串联一个字符串和一个布尔值。

强vs弱

“强类型”的反义词是“弱类型”,这意味着您可以在类型系统周围工作。众所周知,C是弱类型的,因为任何指针类型都可以通过强制转换直接转换为任何其他指针类型。Pascal原本是强类型的,但是设计的监督(未标记的变体记录)在类型系统中引入了漏洞,因此从技术上讲,它是弱类型的。真正强类型语言的示例包括CLU,Standard ML和Haskell。实际上,标准ML已进行了多次修订,以消除在广泛部署该语言后发现的类型系统中的漏洞。

这到底是怎么回事?

总的来说,谈论“强”和“弱”并没有多大用处。类型系统是否存在漏洞与漏洞的确切数量和性质,在实践中出现的可能性以及利用漏洞的后果相比,并不那么重要。实际上,最好完全避免使用术语“强”和“弱”,因为

  • 业余爱好者经常将它们与“静态”和“动态”混为一谈。

  • 显然,有些人使用“弱类型”来谈论隐性转换的相对盛行或不存在。

  • 专业人士无法就术语的确切含义达成共识。

  • 总体而言,您不太可能通知或启发您的听众。

可悲的事实是,在类型系统方面,“强”和“弱”在技术含义上并没有达成共识。 如果要讨论类型系统的相对强度,最好确切讨论提供了什么保证和不提供什么保证。例如,一个很好的问题是:“是否一定要通过调用该类型的构造函数之一来创建给定类型(或类)的每个值?” 在C语言中,答案是否定的。在CLU,F#和Haskell中,是的。对于C ++,我不确定,我想知道。

相比之下,静态类型化意味着在执行程序之前先检查程序,然后在启动程序之前将其拒绝。 动态类型化意味着执行过程中会检查的类型,而类型错误的操作可能会导致程序停止运行或在运行时发出错误信号。静态类型化的主要原因是要排除可能具有此类“动态类型错误”的程序。

一个暗示另一个吗?

从学徒的角度来看,不可以,因为“强”一词实际上没有任何意义。但实际上,人们几乎总是做以下两件事之一:

  • 他们(错误地)使用“强”和“弱”来表示“静态”和“动态”,在这种情况下,他们(错误地)正在交替使用“强类型”和“静态类型”。

  • 他们使用“强”和“弱”来比较静态类型系统的属性。很少有人听到有人谈论“强”或“弱”动态类型系统。除了FORTH,它实际上没有任何类型的类型系统,我无法想到可以颠覆类型系统的动态类型语言。根据定义,这些检查会进入执行引擎,并且在执行每个操作之前都会对其进行检查。

无论哪种方式,如果一个人称一种语言为“强类型”,那么这个人很可能在谈论静态类型的语言。


3
@亚当:显然是不够正确的,不能被否决:)因为克莱斯图斯的答案包含了很多误解(尽管我把最糟糕的错误排除在外),我感到被迫用一个音节的单词来拼写一切……
诺曼·拉姆齐

1
好吧,我对您表示赞赏:)对于当今运行动态语言的VM,即使“编译”一词也不清楚。从技术上讲,Java和C#都被编译两次(JIT),并且都进行某种类型分析。由于VM,在.NET vm中运行的Javascript之类的语言可能更具Typesafe。
亚当·根特

2
我现在很困惑!好吧,亲爱的竞技场大角斗士们,像我这样可怜的灵魂,可以通过以下简单的理解走吗?1.Static:Values在编译时与类型关联,而不是在运行时2.Dynamic:Values在运行时与类型关联,因此值的类型在运行时会发生变化,因此更容易发生与类型转换相关的问题在运行时。3.强/弱:算了!这些不是技术术语,而只是不好的术语。这取决于人们在谈论什么环境。我可以通过这种简单的理解来继续我的生活吗?:(
Saurabh Patil 2014年

“是否一定要通过调用该类型的构造函数之一来创建给定类型(或类)的每个值?” 在C语言中,答案是否定的。有人可以举例说明这种情况在C语言中发生吗?我想这涉及到将指针转换为结构吗?
corazza 2014年

强弱键入:没有此类分类。
劳尔2015年

248

这经常被误解,所以让我澄清一下。

静态/动态打字

静态类型是类型绑定到变量的地方。在编译时检查类型。

动态类型是类型绑定到值的地方。在运行时检查类型。

因此,以Java为例:

String s = "abcd";

s将“永远”成为一个String。在其生命周期中,它可能指向不同的Strings(因为s在Java中是引用)。它可能有一个null值,但绝不会引用IntegerList。那是静态类型。

在PHP中:

$s = "abcd";          // $s is a string
$s = 123;             // $s is now an integer
$s = array(1, 2, 3);  // $s is now an array
$s = new DOMDocument; // $s is an instance of the DOMDocument class

那是动态打字。

强/弱键入

(编辑警报!)

强类型键入是一个没有广泛认同的含义的短语。大多数使用该术语来表示静态类型以外的内容的程序员都使用它来暗示编译器强制执行某种类型规则。例如,CLU具有强大的类型系统,该类型系统不允许客户端代码创建抽象类型的值,除非使用该类型提供的构造函数。C具有某种程度强的类型系统,但是由于程序始终可以将一种指针类型的值转换为另一种指针类型的值,因此它可以被“颠覆”到一定程度。因此,例如,在C中,您可以采用由返回的值malloc()并将其快乐地转换为FILE*,编译器不会尝试阻止您,甚至会警告您您在做任何狡猾的事情。

(最初的回答是关于一个值“在运行时不改变类型”的。系统,这就是所谓的“强更新问题”。)

弱类型意味着编译器不会强制执行键入纪律,或者强制执行很容易被破坏。

该答案的原始内容将弱类型与隐式转换(有时也称为“隐式提升”)结合在一起。例如,在Java中:

String s = "abc" + 123; // "abc123";

这是代码中隐式提升的示例:123在与串联之前被隐式转换为字符串"abc"。可以说Java编译器将该代码重写为:

String s = "abc" + new Integer(123).toString();

考虑一个经典的PHP“开始于”问题:

if (strpos('abcdef', 'abc') == false) {
  // not found
}

这里的错误是strpos()返回匹配的索引,即0。将0强制转换为布尔值false,因此条件实际上为true。解决方案是使用===而不是==避免隐式转换。

此示例说明了隐式转换和动态类型的组合如何使程序员误入歧途。

比较一下Ruby:

val = "abc" + 123

这是一个运行时错误,因为在Ruby中,对象 123 并不仅仅因为它恰好传递给了+方法隐式转换。在Ruby中,程序员必须明确转换:

val = "abc" + 123.to_s

比较PHP和Ruby是一个很好的例子。两种都是动态类型的语言,但是PHP具有很多隐式转换,而Ruby(如果您不熟悉它,也许会令人惊讶)没有。

静态/动态与强/弱

这里的重点是静态/动态轴独立于强/弱轴。人们可能会混淆它们,部分原因是强类型和弱类型的定义不仅不那么明确,而且强者和弱者的确切含义也没有真正的共识。因此,强/弱键入更多地是灰色而不是黑色或白色。

因此,回答您的问题:另一种正确的说法是,静态类型是编译时类型安全,而强类型是运行时类型安全。

原因是静态类型语言的变量具有必须声明的类型,并且可以在编译时进行检查。强类型语言具有在运行时具有类型的值,并且程序员很难在没有动态检查的情况下破坏类型系统。

但重要的是要了解一种语言可以是静态/强,静态/弱,动态/强或动态/弱。


如果您说类型与“ abcd”或1234而不与变量$ s关联,那么与其说$ s是整数或字符串,不如说更好。
斯里尼瓦斯·雷迪Thatiparthy'4

答案清晰,示例清晰。但是,我认为这并不能完全解决人们为什么将强/静视为双对概念的困惑。例如,OP的措辞是“静态类型是否暗示强类型?” 您的答案强调了他们的独立性。要继续澄清为什么强经常与静态配对,诺曼·拉姆齐以前的答案是非常好的: stackoverflow.com/questions/376611/...
JasDev

1
"abc" + 123运行时错误,不是ruby中的编译错误。如果这是一个编译错误,那么ruby将被静态键入。
sepp2k

弱类型的示例需要改进(请参阅我的答案),但否则格式要好。
亚当·根特

在我看来,强打字与弱打字是这样的:强:“ c” + True =运行时错误或编译时错误。弱:“ c” + True =“ b”或“ d”,因为所有内容都被视为原始字节。强:C#,Ruby,C ++弱:汇编,C(由于隐式的空指针)
乔纳森·艾伦2010年

17

两者都是在两个不同轴上的极点:

  • 强类型与弱类型
  • 静态类型与动态类型

强类型表示,a不会自动从一种类型转换为另一种类型。弱类型则相反:Perl可以"123"在数字上下文中使用字符串,方法是将其自动转换为int 123。像python这样的强类型语言不会这样做。

静态类型的方法,编译器在编译时便找出每个变量的类型。动态类型语言仅在运行时确定变量的类型。


6
我不同意。强类型语言是一种在运行时知道类型的语言。弱类型语言是一种不喜欢Assembly的语言。您的示例在第三轴上,“隐式转换与显式转换”。
乔纳森·艾伦,2010年

1
实际上,我同意乔纳森(Jonathan)的观点,但如果您完成了完整的静态分析并且不允许进行强制转换,则不必在运行时将类型强类型化。(请参阅我编辑的答案)。
亚当·根特

1
Python是动态类型化和强类型化语言的一个示例
MaRoBet19年

13

强类型意味着类型之间的转换之间存在限制。静态类型意味着类型不是动态的-创建变量后就无法更改其类型。


为了证明这一点:在强类型语言中,您不能比较“ 5” == 5并使其为真:字符串不是整数。如果可以的话,大多数现代脚本语言都可以动态键入。Tcl / Tk,但是类型较弱-一切都可以视为字符串。
小鲍比桌子

Bobby用弱类型语言“ 5” == 5读取为0x35 == 0x05。换句话说,所有内容都被视为原始字节。
乔纳森·艾伦,2010年

我必须不同意你们俩。拿卢阿 你可以比较“5” == 5,它会返回false,但是快速的转换可以通过进入“5” + 0做
RCIX

12

数据强制不一定表示弱类型,因为有时其语法糖:

上面的Java示例由于类型弱而导致

String s = "abc" + 123;

不是弱类型的示例,因为它确实在做:

String s = "abc" + new Integer(123).toString()

如果要构造一个新的对象,数据强制也不是弱类型。Java是弱类型的一个非常糟糕的例子(任何具有良好反射能力的语言很可能不会弱类型)。因为语言的运行时总是知道类型是什么(异常可能是本机类型)。

这与C不同。C是弱类型的最佳示例之一。运行时不知道4个字节是整数,结构,指针还是4个字符。

语言的运行时真正定义了它是否为弱类型,否则是否为真正的公正意见。

编辑: 经过进一步思考,这不一定是正确的,因为运行时不一定必须在运行时系统中将所有类型都进行分类才能成为强类型系统。Haskell和ML具有完整的静态分析,因此可以潜在地忽略运行时的类型信息。


如果不太为人所知,B可能是更好的例子。
Tom Hawtin-大头钉

Javascript的类型也很弱,但是因为类型太少并且因为您不能真正构造新的类型。
亚当·根特

10

上面已经给出了答案。试图区分强力还是每周和静态还是动态。

什么是强类型VS弱类型?

强类型:不会自动从一种类型转换为另一种类型

在Go或Python中,像强类型语言一样,“ 2” + 8将引发类型错误,因为它们不允许“类型强制”。

弱(松散)类型的:将自动转换为一种类型: 弱类型的语言(如JavaScript或Perl)不会引发错误,在这种情况下,JavaScript将产生'28',而perl将产生10。

Perl示例:

my $a = "2" + 8;
print $a,"\n";

将其保存到main.pl并运行perl main.pl,您将获得输出10。

什么是静态VS动态类型?

在编程中,程序员针对检查变量类型的点定义静态类型和动态类型。静态类型语言是在编译时进行类型检查的语言,而动态类型语言是在运行时进行类型检查的语言。

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

这是什么意思

在Go中,它会在运行时之前键入检查(静态检查)。这意味着它不仅会转换和检查执行代码,还会扫描所有代码,甚至在代码运行之前都会引发类型错误。例如,

package main

import "fmt"

func foo(a int) {
    if (a > 0) {
        fmt.Println("I am feeling lucky (maybe).")
    } else {
        fmt.Println("2" + 8)
    }
}

func main() {
    foo(2)
}

将此文件保存在main.go中并运行它,您将为此收到编译失败消息。

go run main.go
# command-line-arguments
./main.go:9:25: cannot convert "2" (type untyped string) to type int
./main.go:9:25: invalid operation: "2" + 8 (mismatched types string and int)

但是这种情况不适用于Python。例如,以下代码块将在第一次foo(2)调用时执行,而在第二次foo(0)调用时失败。这是因为Python是动态类型的,它只翻译和执行其执行的代码并对其进行类型检查。else块永远不会为foo(2)执行,因此甚至不会查看“ 2” + 8,对于foo(0)调用,它将尝试执行该块并失败。

def foo(a):
    if a > 0:
        print 'I am feeling lucky.'
    else:
        print "2" + 8
foo(2)
foo(0)

您将看到以下输出

python main.py
I am feeling lucky.
Traceback (most recent call last):
  File "pyth.py", line 7, in <module>
    foo(0)
  File "pyth.py", line 5, in foo
    print "2" + 8
TypeError: cannot concatenate 'str' and 'int' objects

8

一个并不暗示另一个。语言是静态的类型这意味着所有变量的类型在编译时是已知的或推断的。

一个类型语言不允许你使用一种类型作为另一个。C是一种弱类型语言,并且是强类型语言所不允许的一个很好的例子。在C语言中,您可以传递错误类型的数据元素,并且不会抱怨。在强类型语言中,您不能。


7

强类型可能意味着变量具有明确定义的类型,并且在表达式中组合不同类型的变量有严格的规则。例如,如果A是一个整数而B是一个浮点数,那么关于A + B的严格规则可能是A被强制转换为浮点数,并且结果以浮点数形式返回。如果A是整数,而B是字符串,则严格的规则可能是A + B无效。

静态类型可能意味着类型是在编译时分配的(或与非编译语言等效的类型),并且在程序执行期间不能更改。

请注意,这些分类不是相互排斥的,的确,我希望它们经常一起出现。许多强类型语言也是静态类型。

请注意,当我使用“可能”一词时,是因为这些术语没有普遍接受的定义。到目前为止,您已经从答案中看到了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.