ChatGPT解决这个技术问题 Extra ChatGPT

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

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

注意在 stackoverflow.com/questions/2351190/… 处几乎重复
Tcl 是强类型的。它只有字符串:P
@nawfal 不,那是字符串类型的;)
什么是Tcl,你们?

N
Norman Ramsey

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

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

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

静态与动态

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

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

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

强对弱

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

这里到底发生了什么?

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

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

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

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

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

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

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

一个是否暗示另一个?

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

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

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

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


@Adam:显然不够正确,不能被赞成:) 因为 Cletus 的回答包含很多误解(尽管我删掉了其中最糟糕的部分),所以我觉得不得不用一个音节的话把所有的东西都拼出来......
好吧,我赞成你:) 即使是“编译”这个词也不是一个清晰的词,今天的虚拟机运行动态语言。从技术上讲,Java 和 C# 都被编译了两次 (JIT),并且都进行了一些类型分析。由于 VM,在 .NET vm 中运行的 Javascript 之类的语言可能更加类型安全。
我现在很困惑!好吧,亲爱的竞技场伟大角斗士,像我这样的可怜的灵魂,可以接受以下简单的理解吗? 1.Static:值在编译时与类型关联,而不是在运行时。2.Dynamic:值在运行时与类型关联,因此值的类型可以在运行时改变~所以更容易出现类型转换相关的问题在运行时。 3.强/弱:算了!这些不是技术术语,只是不好的命名法。这取决于一个人在谈论什么上下文。我能以这种简单的理解继续我的生活吗? :(
“是否保证给定类型(或类)的每个值都是通过调用该类型的构造函数之一创建的?”在 C 中,答案是否定的。有人可以提供在 C 中发生这种情况的示例情况吗?我想它涉及将指针转换为结构?
强类型和弱类型:没有这样的分类。
a
alex

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

静态/动态打字

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

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

所以以Java为例:

String s = "abcd";

s 将“永远”成为 String。在其生命周期中,它可能指向不同的 String(因为 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

那是动态类型。

强/弱打字

(编辑警报!)

Strong typing 是一个没有广泛认同的含义的短语。大多数使用这个术语来表示静态类型以外的东西的程序员都用它来暗示编译器强制执行类型规则。例如,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 中,object 123 被 not 隐式转换只是因为它恰好被传递给 + 方法。在 Ruby 中,程序员必须明确转换:

val = "abc" + 123.to_s

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

静态/动态与强/弱

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

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

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

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


与其说 $s 是整数或字符串,不如说类型与“abcd”或 1234 而不是变量 $s 相关联会更好。
带有清晰示例的出色答案。但是,我认为它并没有完全解决人们为什么会问强/静态作为一对概念的困惑。例如,OP 的措辞“静态类型是否意味着强类型?”你的回答强调了他们的独立性。为了继续澄清为什么强者经常与静态配对,Norman Ramsey 之前的回答非常好:stackoverflow.com/questions/376611/…
"abc" + 123runtime 错误,而不是 ruby 中的编译错误。如果是编译错误,ruby 将是静态类型的。
弱类型示例需要改进(请参阅我的答案),但其他方面的格式很好。
在我看来,强类型与弱类型是这样的:强:“c”+真=运行时错误或编译时错误。弱:“c”+ True =“b”或“d”,因为所有内容都被视为原始字节。强:C#、Ruby、C++ 弱:汇编、C(由于隐式 void 指针)
p
paradocslover

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

强类型与弱类型

静态类型与动态类型

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

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


我不得不不同意。强类型语言是一种在运行时知道类型是什么的语言。弱类型语言是一种不喜欢汇编的语言。您的示例在第三个轴上,“隐式与显式转换”。
实际上很正常,我同意乔纳森,但是如果您进行完整的静态分析并且不允许强制转换,则您不必在运行时使用可用的类型来进行强类型化。 (请参阅我编辑的答案)。
Python是动态类型和强类型语言的一个例子
P
Pshemo

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

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


为了证明这一点:在强类型语言中,您无法比较 "5" == 5 并使其为真:字符串不是整数。如果我没记错的话,大多数现代脚本语言都是强动态类型的。然而,Tcl/Tk 是弱类型的——一切都可以被视为一个字符串。
Bobby,在弱类型语言中,“5”== 5 读作 0x35 == 0x05。或者换句话说,一切都被视为原始字节。
我不得不不同意你们俩。以 Lua 为例;您可以比较 "5" == 5 并且它会返回 false,但是可以通过 "5" + 0 进行快速转换。
L
Leśny Rumcajs

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

什么是强类型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

A
Adam Gent

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

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

String s = "abc" + 123;

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

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

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

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

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

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


B 可能是一个更好的例子,如果不太为人所知的话。
Javascript 也是相当弱的类型,但是因为类型太少而且你不能真正构造新类型。
J
Joe Cannatti

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

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


H
High Performance Mark

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

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

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

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


P
PolarBear2015

恕我直言,最好完全避免这些定义,不仅没有就术语的定义达成一致,确实存在的定义往往侧重于技术方面,例如,是否允许对混合类型进行操作,如果没有,是否存在漏洞绕过限制,例如使用指针按自己的方式工作。

相反,再次强调这是一种观点,人们应该关注以下问题:类型系统是否使我的应用程序更可靠?一个特定于应用程序的问题。

例如:如果我的应用程序有一个名为加速度的变量,那么很明显,如果声明和使用该变量的方式允许将值“星期一”分配给加速度,这是一个问题,因为很明显加速度不能是工作日(并且细绳)。

另一个例子:在 Ada 中可以定义:subtype Month_Day is Integer range 1..31;,Month_Day 类型是弱的,因为它不是 Integer 的独立类型(因为它是一个子类型),但是它仅限于范围 1..31。相反:类型 Month_Day 是新的 Integer;将创建一个独特的类型,它在没有显式转换的情况下不能与整数混合的意义上是强大的 - 但它不受限制并且可以接收无意义的值 -17。所以从技术上讲,它更强大,但不太可靠。当然,可以声明类型 Month_Day 为 new Integer range 1..31;创建一个独特且受限制的类型。