欢迎光临散文网 会员登陆 & 注册

第 5 讲:数据类型(二):字面量和数据类型的关系

2021-03-21 14:02 作者:SunnieShine  | 我要投稿

Part 1 定义

什么是字面量(Literal)?字面量是一种直接写到代码里的数值。在编程的时候,我们直接写的数字符号(包括小数和整数)、原封不动输出的字符串,这些都被称为字面量。只是说,字符串是字符串字面量,而数字呢,则叫做数字字面量。

在这里示例里,25 这个数字是我们直接写到程序代码里的数据信息。这个 25 我们就称为整数字面量。

Part 2 字面量的对应类型

在 C# 的世界里,我们使用的字面量都对应一个“默认的”数据类型。换句话说,即使我们左侧的变量不给出数据类型的名称(不管是 BCL 名称还是关键字),我们总可以通过字面量本身确定变量的类型。

2-1 正整数字面量

我们可以总结出如下两点:

  1. 如果是一个整数字面量的话,那么它默认就是 int 类型的数据;

  2. 如果这个数据可以用范围更小的数据类型表达出来,那么这个数值也可以直接自动赋值给这个类型的变量。

下面我们来看一下,这个解释是什么意思。首先

这个赋值语句下,25 是默认 int 类型的。大家都知道,int 类型和 byte 类型来比较的话,显然 int 范围更大;如果将一个能表示出范围更大的数据类型赋值给一个表示范围较小的数据类型,就可能产生错误,比如说一个 byte 类型的变量,接受了 300 这个数,显然就是不合理的。但是我们通过第二点可以得到,显然例子里的 25 是属于 byte 类型的数据范围的,所以这样的赋值语句,编译器根本不应该告诉你,这是错误的赋值。所以,编译器允许这么赋值。

因此,我通过这则示例告诉你,25 是 int 类型的;而 agebyte 类型的,编译器也允许这么赋值。

当然,25 也可以写成 +25,因为数学上的正号加不加都没关系,因此 C# 也是一样。

2-2 负整数字面量

除了正整数,还有负整数的字面量。和数学上的表达完全一致,我们使用减号来表示负数:

这里的 -13 就是负整数字面量。很有趣的一点是,因为 int 类型的取值范围是包含负数的,因此实际上负整数字面量的默认数据类型依然是 int。而且,它依旧遵循前文提到的“范围最小赋值原则”(说白了就是前面那一节内容里面的那个第二点)。

2-3 长整数字面量

C# 的语法是严谨的。由于前文的整数字面量是默认 int 类型的,那么我们就无法直接写一个超出 int 范围的整数字面量。但是 long 类型必须要赋一个初始数值的话,怎么办呢?

我们使用后缀字母 L(或者小写 l)来告诉编译器,这个字面量是 long 类型的。

显然,这里的 78 亿是超出了 int 的取值范围的(int 最大才到 2147483647),因此如果我们直接写上 7800000000000 的话,就会出现编译器错误。因此,我们需要强制追加后缀 L 来告诉编译器,这里的这个数字是 long 类型。这样的话,左侧的变量就可以正常接受字面量数值了。

同理,如果数字为负数,依旧添加负号即可:long p = -1000000000000L

另外,这么赋值也是没问题的:long p = 13L,但是反过来就不对了:如果右侧是 long 的字面量,而左边是 int 类型,即使范围合适,依然不允许赋值(即错误赋值):int p = 13L。这是因为,既然 13 是正常的 int 字面量,那么为什么要追加 L 后缀,然后再赋值给 int 类型呢?这不是就绕了一步吗?因此编译器不允许我们这么搞。

2-4 无符号整数字面量

我们知道,一个整数字面量是没办法确保是不是正整数的。为了确保字面量本身就可以表示无符号类型,那么就产生了这样的字面量。

比如,这样。我们使用 U 字母(或小写 u)来表示和暗示这个字面量是 uint 类型的(即无符号整数)。

不过,它和最开始就说的正整数字面量有区别吗?是的,有区别。前面的正整数字面量默认类型是 int 类型,而这里的无符号的整数字面量默认是 uint 类型的。正是因为这个区别,因此我们如下的四种组合里,有一种就是不正确的:

  • int age = 25;(正确)

  • int age = 25U;(错误)

  • uint age = 25;(正确)

  • uint age = 25U;(正确)

这里的 int age = 25U 是错误的赋值。因为 int 类型和 uint 类型并不能说“范围完全兼容”,uint 类型只包含正整数,因此范围比 int 类型多了一截;而 int 可表示负数,所以 int 可以表达负数。

显然,这样的数据类型是无法完整兼容的,因此我们无法通过字面量来把 uint 赋值给 int 类型。

另外,由于无符号字面量本身就是不可负的,因此无符号字面量的前面是不能加负号的。换句话说,-25U 是错误的写法;但是,带正号可以:+25U

最后,U 后缀和 L 后缀是可以混用的。不论你的 U 字母和 L 字母的顺序如何,大小写如何,只要写在一起作为字面量后缀,就可以表示一个字面量是 ulong 类型的。

同样地,这里的带 UL 后缀的字面量也无法赋值给范围较小类型的其它整数类型。比如 uint age = 25UL 就是错误的写法。

2-5 浮点数字面量

浮点数类型有三种,所以有三种不同的字面量类型。

  • 使用 fF 后缀,表示一个小数是 float 类型的;

  • 使用 dD 后缀,表示一个小数是 double 类型的;

  • 使用 mM 后缀,表示一个小数是 decimal 类型的;

  • 如果任何后缀都没有的小数表达式,默认就是 double 类型的。

从精度上和数据取值范围上来说,double 都比起 float 类型要大,因此 float 类型的字面量可以赋值给 double,但反过来不行:

这样的赋值里,g1g2g3 的赋值是错误的。因为 float 类型范围较小,却接受了一个 double 类型的字面量。

另外,这里简单说一下 decimal 类型字面量。decimal 类型的取值范围比较小,但精度特别高(能精确到 29 位),所以它和 float 还有 double 范围上并不能直接兼容。和 uint 还有 int 的赋值逻辑一样,我们不能将 decimal 字面量赋值给 floatdouble 类型的变量;反过来把 floatdouble 类型的字面量赋值给 decimal 类型的变量也不可以。

这里,后面四种赋值全部都是错误的。

如果整数部分是 0 的小数可以不写这个 0,即比如说 0.37 可以写成 .37;但是小数部分就算为 0,也不能省略:30.0 不能写 30.,这个写法 C 语言允许,但 C# 里不行。

2-6 整数和浮点数

前面我们一直说的是整数和小数的字面量,但它们没有互相赋值。

思考一下,decimal d = 30U; 会不会成功呢?C# 里规定,所有前文提到的字面量全部都可以通过赋值的方式赋值给任何浮点数类型,但反过来的话,任何浮点数类型的数据都不可以赋值给任何整数的数据类型。因为浮点数的范围我们没有在前文里提及,因此我们无法介绍这一点。

大概来说,float 这个最大可以到大约 10 的 38 次方(再怎么说都超出 ulong 最大的整数的数据取值范围了),double 能达到大约 10 的 308 次方,而 decimal 的最大值大约是 。所以范围上来说,最小范围的 float 类型,也可以完美覆盖任何整数数据类型的数据,因此,用浮点数类型的变量接受整数类型的字面量,是怎么都允许的;但反过来因为数据的取值范围不兼容的缘故,这样就不行了。

稍微啰嗦一下,30 和 30.0 的区别是,在 C# 里,30 是整数(int 字面量),而 30.0 是浮点数(double 字面量)。因此,double d = 30double d = 30.0double d = 30D 的赋值意义不太一样。后面两种是同样的模式(因为都是 double 类型字面量),而第一个则是通过“浮点数接受整数类型的变量”这个规则而赋值的。

2-7 科学计数法字面量

为了保证数据能够简单表达,C# 允许使用科学计数法类似的写法来表达一个浮点数。举个例子:

在这里例子里,1E5 称为科学计数法。科学计数法的表达规则是这样的:如果一个数学上的科学计数法表达是 a * 10 的 b 次方 的话:

  • 部分使用字母 Ee 代替;

  • a 和 b 则按照科学计数法的基本写法即可。

比如 1E5 就是 10 的 5 次方。当然,如果 b 是负数的话,科学计数法里这样表达的数据就是一个小数了。比如 1E-3 就是 10 的 -3 次方,即 1/1000(0.001)。

2-8 字符和字符串的字面量

因为这一个内容牵扯到字符串的使用,因此这里我们不作介绍,我们在下一节就会介绍它们。

2-9 布尔型字面量

最后还剩下布尔型数据的字面量没有说了。因为布尔型只用来表示对错,所以只有(True)和(False)两个结果。在 C# 里,直接采用 truefalse 这两个关键字就可以充当了。

就是这样的。前面的文章其实就已经说过了,不过这里再说一下。这里的 truefalse 是布尔型里唯有的两个字面量。

另请注意,因为它只表示对错,因此跟整数、浮点数完全没有关联,因为我们无法把布尔型数据赋值给任何浮点数数据类型和任何整数数据类型;反之亦然。

这两种赋值都是错的。bool 字面量只能赋值给 bool 类型的变量。

Part 3 总结

我相信你根本记不住前面的东西。所以我这里做一个简要的回顾和归纳。

3-1 字面量默认类型

  • 整数字面量默认是 int 类型的(不论带不带正负号,都是 int 类型的);

  • L 后缀(或 l)的整数字面量是 long 类型的(不论带不带正负号);

  • U 后缀(或 u)的整数字面量是 uint 类型的(这样的话,只能带正号,或者不要符号);

  • 同时带有 UL 后缀的整数字面量是 ulong 类型的(这两个后缀记号不需要考虑先后顺序,也不需要考虑大小写);

  • Ff 后缀的字面量是 float 类型的;

  • Dd 后缀(或不带后缀的小数)的字面量是 double 类型的;

  • Mm 后缀的字面量是 decimal 类型的;

  • 科学计数法字面量默认是 double 类型的;

  • bool 字面量只有两个:truefalse,且均使用关键字表示。

3-2 字面量赋值关系

  • 所有字面量的默认类型,可以直接赋值给这个类型的变量;

  • 不带后缀的整数字面量是可以允许在兼容范围的时候,赋值给较小数据类型的变量;

  • 带后缀的整数字面量,不能赋值给范围较小的变量(不论是否兼容取值范围);

  • double 类型的变量能接受 float 字面量和 double 类型的字面量的赋值,但反之不然;

  • decimal 类型的变量只能接受 decimal 字面量,其它的浮点数字面量都不可以;

  • 任何整数类型的字面量均可以直接赋值给任何浮点数类型,但反之不然;

  • 由于科学计数法是 double 类型的字面量,所以它的赋值规则和 double 字面量的规则是一样的;

  • bool 字面量不能赋值给其它任何类型的变量,反之亦然。


第 5 讲:数据类型(二):字面量和数据类型的关系的评论 (共 条)

分享到微博请遵守国家法律