静态、动态、强和弱数据类型介绍

337 阅读7分钟

Introduction to Static, Dynamic, Strong and Weak Data Types

本文将解释什么是数据类型,当我们谈论数据类型时,术语 "静态"、"动态"、"强 "或 "弱 "是什么意思,以及我们为什么要关心这些。

什么是数据类型?

如果你做过任何编程,你肯定见过变量、参数或从函数返回的值。它们在编程世界中无处不在。许多程序员开始使用它们时,并不真正了解他们在引擎盖下向计算机指定什么。当定义这些值时,程序员是在向计算机指定一个变量的名称,同时也告诉计算机它是什么类型的数据。它是一个整数吗?是一连串的字符吗?它是一个单一的字符还是一个复杂的类型,如Point ? 为了理解数据类型,我们可能会发现把这个术语翻过来,把它看作是我们正在处理的 "数据类型 "会更容易一些。

如果你在网上浏览了一些信息,你可能已经读到了关于 "静态 "与 "动态 "数据类型,以及 "强 "与 "弱 "数据类型的矛盾信息。它们并不是一回事。当我们浏览下面的不同术语时,请记住,一种语言可以包括静态/动态和强/弱数据类型的组合。它们并不排斥。例如,一种语言可以是静态和强的,也可以是静态和弱的。但在我们对这些术语的定义走得太远之前,我们为什么要关心呢?

为什么我们要关心数据类型?

每一种编程语言都有一个数据类型系统。没有类型系统,计算机就不知道如何表示我们程序中的数据。他们不知道如何将这种类型的数据添加到其他类型的数据中,甚至不知道如何存储数据。通过指定一个变量为整数,计算机知道它需要多少个字节来表示这个值,更重要的是,它可以如何对其进行操作。将两个整数相加与将两个字符串相加是一个不同的操作。计算机知道如何处理数据的唯一方法是知道它所处理的数据类型。

你可以在不太了解底层类型系统的情况下开始编程。这就是这些高级语言的魅力之一。但是,了解你所处理的数据类型,以及如何最好地表示你所处理的数据,会带来巨大的优势,例如下面列出的那些:

  • 你将拥有更有效的程序,更好地利用内存和存储。知道一个整数数组比一个双数数组所占的空间要小,在处理内存或硬盘上的非常大的数组时,可以节省数千字节甚至兆字节的空间。

  • 它可以帮助你破译调试信息,更好地理解与数据类型有关的问题。当程序抱怨它不能将两个数字相加,因为其中一个数字是一个字符串,你就明白了原因。学习这个事实将帮助你避免一开始就犯试图将数字加到字符串的错误。

  • 一旦你知道类型是如何工作的,你就可以像电影*《黑客帝国》*中的尼奥一样,知道如何弯曲规则。你会知道当把一个整数加到一个字符上时,你如何能得到另一个字符,以及为什么这样做。

静态与动态数据类型系统

所以,数据类型是我们告诉计算机我们正在处理的数据类型的方式。然而,当程序员说一种语言的类型系统是静态或动态的,他们指的是什么?

静态数据类型语言是指那些要求程序员在创建数据(无论是变量、参数、返回值等等)时明确定义数据类型的语言。通常,这些类型在程序的生命周期中也被固定为该类型,它们不会改变其类型。我们来看看一个例子:

int myNumber = 42;              // integer data type
string name = "Rocky Balboa";   // string data type
final double PI = 3.141592;     // double data type

// Function takes two integer data types, returns an integer data type
public int add(int a, int b) {
    return a + b;
}

上面这个例子显示了几个被定义的变量,以及一个将两个数字相加的函数的例子。正如你所看到的,我们明确地告诉语言(在这种情况下,Java),我们正在处理整数、字符串和双数。如果没有这些对编译器的提示,编译器将不知道如何处理myNumber 。这只是一个对我们有意义的名字,而不是计算机。

一些静态类型的语言包括Java、C#、C++和Go。但这些只是众多语言中的一小部分。

让我们将其与动态数据类型语言进行对比。下面是一个例子:

$myNumber = 42;           // integer data type
$name = "Rocky Balboa";   // string data type
$PI = 3.141592;           // float data type

// Function takes two integer data types, returns an integer data type
function add($a, $b) {
    return $a + $b;
}

那么,所有的类型都去哪儿了?在上面这个例子中,我们看到我们在PHP这种动态类型语言中的变量并没有明确说明它们是什么类型的数据。如果我们不告诉 PHP 数据类型,它怎么知道呢?好吧,它根据分配给它的值来猜测。它可以正确地猜到$myNumber 是一个整数,因为值42是一个整数。

那函数呢?它也是根据传递给它的值进行猜测的。这意味着add() 可以接收两个整数并返回一个整数,或者它也可以接收两个浮点数并返回一个浮点数。这些类型是推断出来的,甚至可以在运行时改变。我们以后可以在同一个程序中说,$myNumber 等于Tom ,它将让我们把变量切换成一个字符串。

许多动态语言中的几个包括JavaScript、PHP、Python和Ruby。

为什么你更喜欢静态的而不是动态的,或者相反?

在静态数据类型语言的情况下,通过明确告诉编译器你所处理的数据类型,它可以在部署前很久就发现代码中的常见错误和误差。如果你把一个值定义为整数,另一个定义为字符串,编译器可以在编译时发现一个加法错误,而不会让你完成程序的构建。这是好事,因为你越早发现错误,你的代码就越强大,你和你的客户修复它的成本就越低。早期修复比后期部署后修复要容易得多。

所以,静态的方式是正确的?好吧,代价是你必须在使用前明确定义所有的东西。你必须输入更多的代码,你必须事先知道你要处理的数据类型(并不总是你知道的),你必须知道你的操作中会发生什么。你必须知道1 / 3 会给你0 ,而不是.33333 ,诸如此类的事情。

动态语言在这个领域给你增加了灵活性。程序员经常把它们描述为 "更有表现力"。例如,在PHP中,你会得到.3333... ,正如你所期望的那样。然而,问题是,如果解释器在数据类型上做了错误的猜测,你必须知道它。否则它就会偷偷地溜走。由于我们不能抓住一切,动态语言中的代码往往更容易出错,也更脆。这些动态语言中的数据类型通常在运行时确定。这使得许多错误在到达生产环境之前很难被发现。它可能在你的本地开发机器上运行良好,但生产运行环境可能略有不同,产生一些不同的解释器的猜测。

JavaScript是一种被认为是动态的语言。随着TypeScript(JavaScript的超集)的引入,程序员引入了为变量明确声明数据类型的想法,以使语言更加静态。随着JavaScript的普及--甚至超越了浏览器和Node.js等工具--程序员希望增加静态数据类型的好处,以消除JavaScript在处理数据类型时的一些错误猜测。在处理数据及其类型时,JavaScript因其一些错误的猜测而臭名昭著。这是一个让JavaScript这种动态语言变成更像静态类型语言的例子,可以及早发现错误,从而使代码更加健康。鉴于JavaScript在Node.js的帮助下正在进入服务器端应用程序,这就更加重要了。

简而言之,静态数据类型给你一个严格的环境,通常产生更强大的代码。动态语言给了你灵活性和更快地编写代码的能力,但如果你不小心检查你的类型,就会导致更容易出错的代码。