类型转换
复习
- 类型系统:值的集合与允许的操作
- 表达式的类型检查:沿树检查类型
- 函数与控制流的语义检查:核对类型匹配
TL;DR
- 类型转换让不同类型的值参与运算
- 隐式转换由编译器自动进行,须遵循规则
- 显式转换由程序员明确写出
- 有些转换安全,有些会丢失信息
正文
类型检查要求类型匹配。可现实中,不同类型难免要相遇,比如 1 + 2.5——一个整数加一个浮点数,怎么办?这就需要类型转换(type conversion)。
自动完成的转换
有些转换,编译器会自动替我们完成,这叫隐式转换。
比如 1 + 2.5,编译器通常会把整数 1 提升成浮点数 1.0,再做浮点加法,结果是 3.5。这个过程是自动的,程序员不用管。
但隐式转换必须有章可循。编译器不是随便乱转,而是遵循一套预先定好的规则(通常叫类型提升规则)。而且,它只会自动做那些“安全”的转换——所谓安全,是指转换不会丢失信息,一定有确定的结果。
明确写出的转换
另一些转换,需要程序员明确写下,这叫显式转换(也叫强制类型转换),比如把浮点数强制取整:
(int) 3.7 → 3
这种转换由程序员主动要求,编译器照办。之所以要“强制”,往往是因为这种转换有风险或不精确。
哪些转换要小心
判断一个转换危不危险,关键看信息会不会丢失:
- 较安全的:小范围整数转大范围整数(不会丢值),整数转浮点(多数情况不丢)
- 要谨慎的:浮点转整数(小数部分被直接丢弃)
- 很危险的:大范围转小范围(可能溢出,结果完全变样)
这正是为什么“浮点转整数”“大转小”这类,语言往往要求你显式写出来:不是不让你转,而是提醒你“这里可能丢东西,你想清楚了吗?” 用一点点书写成本,换你对潜在风险的注意。
这又回到那个熟悉的观念:类型系统不只是拦错误,也是在替你标出“这里要小心”。
思考题 1
隐式类型转换和显式类型转换,分别由谁决定?
思考题 2
为什么“浮点数转整数”通常是一种需要谨慎的转换?
小结
知识点
- 类型转换让不同类型的值参与运算
- 隐式转换由编译器按规则自动完成,通常只做安全转换
- 显式转换由程序员明确写出
- 判断风险的关键是有无信息丢失
参考资料
- Wikipedia(zh):类型转换:在不同类型之间转换值
- Wikipedia(zh):隐式类型转换:由编译器自动完成的类型转换
思考题答案(仅供参考)
思考题 1
隐式转换由编译器根据预设规则自动决定;显式转换由程序员在代码中明确写出,表示“我确实要这样转”。前者只做安全的转换,后者允许有风险的转换。
思考题 2
因为它会直接丢弃小数部分,把 3.7 变成 3,造成精度损失。这种转换不是“值相等”的,需要程序员明确知道并接受这种损失,因此通常要求显式写出。
协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
封面图
设计师 | 南国微雪