另外,是否有人暗示对方?
答案 0 :(得分:454)
答案 1 :(得分:225)
这经常被误解,所以让我清楚一点。
静态类型是类型绑定到变量的位置。在编译时检查类型。
动态类型是类型绑定到值的位置。在运行时检查类型。
所以在Java中例如:
String s = "abcd";
s
将“永远”成为String
。在它的生命中它可能指向不同的String
s(因为s
是Java中的引用)。它可能具有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*
,并且编译器不会试图阻止你 - 甚至警告你,你正在做任何狡猾的事情
(最初的答案说的是“在运行时不改变类型”这个值。我认识很多语言设计者和编译器编写者,并且不知道在运行时谈到值改变类型的那个,除了可能是一些非常先进的研究类型系统,这被称为“强烈更新问题”。)
弱打字意味着编译器不会强制执行输入discpline,或者可能很容易破坏强制执行。
这个答案的原文将隐式转换(有时也称为“隐式促销”)与弱打字混为一谈。例如,在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(如果你不熟悉它可能会令人惊讶)不会。
这里的要点是静态/动态轴独立于强/弱轴。人们可能会混淆他们,部分原因是因为强类型和弱类型不仅没有明确定义,对于确切的强弱意味着什么也没有真正的共识。因此,强/弱打字更像是灰色而不是黑色或白色。
所以回答你的问题:另一种看待 正确的方法是说静态类型是编译时类型安全,强类型是运行时类型安全。
原因是静态类型语言中的变量具有必须声明的类型,并且可以在编译时进行检查。强类型语言的值在运行时具有类型,并且程序员很难在没有动态检查的情况下破坏类型系统。
但重要的是要理解语言可以是静态/强,静态/弱,动态/强或动态/弱。
答案 2 :(得分:15)
两者都是两个不同轴上的极点:
强类型表示不会自动从一种类型转换为另一种类型。弱类型是相反的:Perl可以在数字上下文中使用类似"123"
的字符串,通过自动将其转换为int 123
。像python这样的强类型语言不会这样做。
静态类型表示编译器在编译时计算出每个变量的类型。动态类型语言只能在运行时找出变量的类型。
答案 3 :(得分:11)
强类型表示类型之间的转换之间存在限制。静态类型意味着类型不是动态的 - 一旦创建变量,就无法更改变量的类型。
答案 4 :(得分:11)
数据强制并不一定意味着弱类型,因为有时它的合成糖:
由于
,Java上面的示例被弱化String s = "abc" + 123;
不是弱类型的例子,因为它真的在做:
String s = "abc" + new Integer(123).toString()
如果要构建新对象,数据强制也不是弱类型。 Java是弱类型的一个非常糟糕的例子(并且任何具有良好反射的语言很可能不会被弱类型化)。因为语言的运行时总是知道类型是什么(异常可能是本机类型)。
这与C不同.C是弱类型的最好例子之一。运行时不知道4个字节是整数,结构,指针还是4个字符。
该语言的运行时确实定义了它的弱类型,否则就是它的真正意见。
编辑: 经过进一步思考后,这不一定是正确的,因为运行时不必将运行时系统中所有类型都设置为强类型系统。 Haskell和ML有这样完整的静态分析,他们可以从运行时省略类型信息。
答案 5 :(得分:8)
强类型可能意味着变量具有明确定义的类型,并且存在关于在表达式中组合不同类型的变量的严格规则。例如,如果A是整数而B是浮点数,那么关于A + B的严格规则可能是A被强制转换为浮点数并且结果作为浮点数返回。如果A是整数而B是字符串,则严格规则可能是A + B无效。
静态类型可能意味着类型是在编译时分配的(或者是非编译语言的等效类型),并且在程序执行期间不能更改。
请注意,这些分类并不相互排斥,实际上我希望它们经常在一起发生。许多强类型语言也是静态类型的。
请注意,当我使用“可能”这个词时,这是因为这些术语没有普遍接受的定义。正如你已经从答案中看到的那样。
答案 6 :(得分:6)
一个并不意味着另一个。对于静态类型的语言,这意味着所有变量的类型在编译时是已知的或推断的。
强类型语言不允许您将一种类型用作另一种类型。 C是一种弱类型语言,是强类型语言不允许的一个很好的例子。在C中,您可以传递错误类型的数据元素,它不会抱怨。在强类型语言中你不能。
答案 7 :(得分:0)
上面已经给出了答案。试图区分强势概念与周概念以及静态概念与动态概念。
强类型输入:不会自动从一种类型转换为另一种类型
在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