Answers:
在动态类型的系统中,值在运行时具有类型,而变量和函数则没有。在静态类型的系统中,变量和函数具有已知的类型,并在编译时进行检查。例如Python x
可以是任何东西 ; 在运行时,如果是1
数字,则为"foo"
字符串。您只会知道x
在运行时是哪种类型,并且每次运行程序时它都可能不同。在Java之类的语言中,您将编写int x
if是否x
为数字,并且您会在编译时知道x
始终必须为int
。
“显式”和“隐式”类型均指静态类型系统。静态系统的定义特征是类型在编译时是已知的,但不一定必须将其写出。在Java中,类型是显式的-您必须将它们写出来。因此,在Java中,方法可能类似于:
public int foo(String bar, Object baz) { ... }
这些类型在编译时(静态)和写入(显式)时都是已知的。但是,有些语言也不会强制您将类型写出。他们可以从函数的主体及其使用方式推断出函数的类型。一个示例是OCaml,您可以在其中编写如下内容:
let foo x = x + 1
自从您使用以来+
,OCaml就能确定这x
必须是int
全部。因此,类型foo
(foo : int -> int
)是在编译时已知,就像Java示例。它是完全静态的。但是,由于编译器可以自行确定类型,因此您不必自己写出来:它们是隐式的。
简而言之:类型系统是显式的还是隐式的是静态系统的属性。这与类型系统是动态的还是静态的完全不同。
通常,您的类型系统有时是显式的,有时是隐式的。
例如,我相信C#可以让您使用var
关键字来推断类型。因此int x = 10
,您可以编写而不是编写,var x = 10
而编译器会发现这x
必须是一个int
。C ++与做了类似的事情auto
。这些系统通常是显式的,但有一些推断。
另一方面,有些系统通常是隐式的,但有时会迫使您写出类型签名。Haskell是一个很好的例子。大多数时候,Haskell可以为您推断类型。但是,有时您可以编写含糊不清的代码,例如show . read
,Haskell无法自行确定类型。在这种情况下,您将不得不明确指定show
或的类型read
。此外,类型系统的一些更高级的功能(例如rank-n多态性)使推理无法确定-也就是说,不能保证暂停。这意味着使用此功能的代码通常需要显式类型签名。
静态与动态描述何时检查类型(在编译时或执行时或多或少)
标称与结构描述了两种类型何时被视为相同。
(而且有一些变体,最著名的是结构类型变体,它仅考虑使用的是什么,而不是整个类型,即鸭子类型)。
四种组合(静态标称,静态结构,动态标称,动态结构)是可能的,并且语言常常不仅仅在一个类中,而在其他方面具有某些方面。
例如,当您考虑使用模板时,C ++的类型系统是静态的,通常是名义上的但结构性的(并且您可以将C ++概念中的部分问题视为希望从鸭子类型化到结构形式的完整形式以及那些想要进行名义打字的人。使用类和继承可以在某些情况下使用动态类型和名义类型。
动态类型系统经常使用的语言是结构化类型,但CLOS是名义上的方面。