此外,这两者是否相互暗示?
他们(不正确地)使用“强类型”和“弱类型”来表示“静态类型”和“动态类型”,因此他们(不正确地)将“强类型”和“静态类型”交替使用。
他们使用“强类型”和“弱类型”来比较静态类型系统的属性。很少听到有人谈论“强类型”或“弱类型”的动态类型系统。除了FORTH之外,我想不出有哪种动态类型语言的类型系统可以被破坏。从某种意义上讲,在执行引擎中内置了这些检查,并且在执行每个操作之前都会进行检查。
无论如何,如果某人称一种语言为“强类型”,那么这个人很可能在谈论一种静态类型的语言。
这个经常被误解,让我来澄清一下。
静态类型是指类型与变量绑定。类型在编译时检查。
动态类型是指类型与值绑定。类型在运行时检查。
所以例如在Java中:
String s = "abcd";
s
将永远是一个 String
。在其生命周期中,它可能指向不同的 String
(因为在 Java 中,s
是一个引用)。它可能具有 null
值,但它永远不会引用一个 Integer
或 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";
这段代码是隐式提升的一个例子:在与"abc"
连接之前,123被隐式转换为字符串。可以认为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则没有(如果你不熟悉Ruby,这可能会让你感到惊讶)。两者均位于不同轴线上:
强类型意味着变量不会自动转换为另一种类型。弱类型则相反:Perl可以将一个字符串像"123"
在数字环境中使用,并自动将其转换为int 123
。像Python这样的强类型语言不会这样做。
静态类型意味着编译器在编译时确定每个变量的类型。动态类型语言只在运行时才确定变量的类型。
强类型指类型之间的转换受到限制。
静态类型意味着类型不是动态的 - 一旦变量被创建,就无法更改其类型。
强类型:不会自动从一种类型转换为另一种类型。
像 Go 或 Python 这样的强类型语言,"2" + 8 将引发类型错误,因为它们不允许 "类型强制转换"。
弱类型:将自动转换为一种类型到另一种类型:
像 JavaScript 或 Perl 这样的弱类型语言不会抛出错误,在这种情况下 JavaScript 会返回 '28',Perl 则会返回 10。
Perl 示例:
my $a = "2" + 8;
print $a,"\n";
将它保存为main.pl并运行perl main.pl
,您将获得输出10。
在编程中,程序员使用静态类型和动态类型来描述变量类型检查的时间点。静态类型语言是指在编译时进行类型检查的语言,而动态类型语言是指在运行时进行类型检查的语言。
这意味着什么?
在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
数据类型转换并不一定意味着弱类型,因为有时它只是语法糖:
上述Java的例子并不代表它是弱类型语言,因为Java实际上是强类型语言。
String s = "abc" + 123;
不是弱类型示例,因为它确实在执行:
String s = "abc" + new Integer(123).toString()
如果你正在构建一个新对象,数据强制转换也不是弱类型的。 Java是弱类型的很糟糕的例子(任何具有良好反射的语言都可能不是弱类型的)。因为语言的运行时始终知道类型是什么(例外情况可能是原生类型)。
这与C不同。C是最好的弱类型示例之一。运行时不知道4个字节是整数、结构体、指针还是4个字符。
语言的运行时真正定义了它是否是弱类型,否则这只是观点。
编辑: 经过进一步思考,这并不一定正确,因为运行时不必将所有类型重新编写到运行时系统中才能成为强类型系统。 Haskell和ML具有完整的静态分析功能,因此可以从运行时中省略类型信息。
两者并不意味着相同。对于一种被静态类型化的语言,这意味着在编译时可知或推断出所有变量的类型。
强类型的语言不允许您将一种类型用作另一种类型。C 是一个弱类型的语言,是强类型语言所不允许的良好例子。在 C 中,您可以传递错误类型的数据元素而不会报错。而在强类型语言中则不行。
强类型可能意味着变量具有明确定义的类型,并且在表达式中组合不同类型的变量时有严格的规则。例如,如果A是整数而B是浮点数,则A+B的严格规则可能是A转换为浮点数并将结果作为浮点数返回。如果A是整数而B是字符串,则严格规则可能是A+B无效。
静态类型可能意味着类型在编译时(或非编译语言的等效方式)分配,并且在程序执行期间不能更改。
请注意,这些分类不是互斥的,事实上我经常希望它们一起发生。许多强类型语言也是静态类型。
请注意,当我使用“可能”一词时,这是因为没有普遍接受的这些术语的定义。正如您到目前为止所看到的答案一样。
Tcl
吗? - carloswm85