540

另外,一个是否意味着另一个?

4

8 回答 8

654

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

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

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

静态与动态

与静态类型相反的是“动态类型”,这意味着

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

例如,动态类型语言Lua具有字符串类型、数字类型和布尔类型等。在 Lua 中,每个值都只属于一种类型,但这并不是所有动态类型语言的要求。在 Lua 中,允许连接两个字符串,但不允许连接一个字符串和一个布尔值。

强对弱

“强类型”的反义词是“弱类型”,这意味着您可以绕过类型系统。C 是出了名的弱类型,因为任何指针类型都可以简单地通过强制转换转换为任何其他指针类型。Pascal 本来打算是强类型的,但是设计中的疏忽(未标记的变体记录)在类型系统中引入了一个漏洞,因此从技术上讲它是弱类型的。真正强类型语言的示例包括 CLU、标准 ML 和 Haskell。事实上,标准 ML 已经进行了多次修改,以消除在语言广泛部署后发现的类型系统中的漏洞。

这里到底发生了什么?

总的来说,谈论“强”和“弱”并没有多大用处。类型系统是否存在漏洞并不重要,而是漏洞的确切数量和性质、它们在实践中出现的可能性以及利用漏洞的后果是什么。在实践中,最好完全避免使用“强”和“弱”这两个词,因为

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

  • 显然,某些人使用“弱类型”来谈论隐式转换的相对普遍性或缺失。

  • 专业人士无法就这些术语的确切含义达成一致。

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

可悲的事实是,当涉及到类型系统时,“强”和“弱”在技术含义上并没有普遍认同。 如果您想讨论类型系统的相对强度,最好准确讨论提供和不提供的保证。例如,一个很好的问题是这样的:“是否保证给定类型(或类)的每个值都是通过调用该类型的构造函数之一创建的?” 在 C 中,答案是否定的。在 CLU、F# 和 Haskell 中是肯定的。对于 C++,我不确定——我想知道。

相比之下,静态类型意味着程序在执行之前会被检查,并且程序在启动之前可能会被拒绝。 动态类型意味着执行过程中检查的类型,并且类型不佳的操作可能会导致程序停止或以其他方式在运行时发出错误信号。静态类型的一个主要原因是排除可能有这种“动态类型错误”的程序。

一个是否暗示另一个?

在迂腐的层面上,不,因为“强大”这个词实际上并没有任何意义。但在实践中,人们几乎总是做以下两件事之一:

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

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

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

于 2010-04-23T05:17:45.550 回答
284

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

静态/动态打字

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

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

所以以Java为例:

String s = "abcd";

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

在 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,因此条件实际上为真。解决方法是使用===而不是==避免隐式转换。

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

将其与 Ruby 进行比较:

val = "abc" + 123

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

val = "abc" + 123.to_s

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

静态/动态与强/弱

这里的重点是静态/动态轴独立于强/弱轴。人们可能会混淆它们,部分原因可能是强类型与弱类型的定义不仅不太明确,而且对于强类型和弱类型的确切含义也没有真正的共识。出于这个原因,强/弱类型更像是灰色阴影,而不是黑色或白色。

所以回答你的问题:另一种看待这个问题的方式是正确的,那就是静态类型是编译时类型安全,而强类型是运行时类型安全。

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

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

于 2010-04-22T12:10:34.793 回答
45

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

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

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

静态类型意味着编译器在编译时计算出每个变量的类型。动态类型语言仅在运行时确定变量的类型。

于 2010-04-22T12:11:07.420 回答
25

类型意味着类型之间的转换之间存在限制。

静态类型意味着类型不是动态的 - 一旦创建了变量,您就无法更改它的类型。

于 2010-04-22T12:07:53.677 回答
14

数据强制并不一定意味着弱类型,因为有时它的语法糖:

上面的 Java 被弱类型化的例子是因为

String s = "abc" + 123;

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

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

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

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

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

编辑: 经过进一步思考,这不一定是真的,因为运行时不必将运行时系统中的所有类型都具体化为强类型系统。Haskell 和 ML 具有如此完整的静态分析,以至于它们可以潜在地从运行时省略类型信息。

于 2010-04-22T12:23:47.957 回答
14

上面已经给出了答案。试图区分强与周以及静态与动态概念。

什么是强类型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
于 2019-03-07T23:35:01.780 回答
11

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

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

于 2010-04-22T12:11:05.400 回答
8

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

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

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

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

于 2010-04-22T12:13:15.200 回答