知识星球里有朋友向我提问:
ABAP 代码 IF 0 = '0.4', 为什么条件成立?也就是说,为什么 ABAP 认为,0 等于 '0.4'?
下列代码打印 true:
IF 0 = '0.4'.
WRITE:/ 'true'.
ENDIF.
要解释这个现象,不能凭空臆测。一切都可以在 ABAP 帮助文档中找到答案。
首先,符号 = 在 ABAP 里有两种用法,一是赋值操作,二是比较操作,即 comparison. 本文场景显然是后者。
比较的对象是 0 和 '0.4'.
前者数据类型是 int,后者是类型为 c 的字面量(literal), 长度为 3.
数学里严格意义上的比较操作,比较的两个操作数必须为同一类型,比较才有意义。
如果操作数类型不一致,不同的编程语言有不同的处理机制。
对于 ABAP 而言,这种场景下,会将不同的数据类型进行统一。
那么类型统一的具体规则是什么?在 ABAP 帮助文档里有讲。
根据关键字 EQ 进行搜索,在 ABAP 帮助文档中找到 Comparison Rules 即比较规则。因为 0 和 '0.4' 都属于简单数据类型,即 Elementary Data Types,所以进入对应的帮助文档区域。
在帮助文档 Comparison Type of Character-Like Data Objects 的文档里,有一个表格,定义了数据类型统一的规则。
从表格中获悉,i 和 c 类型的变量进行比较时,两个操作数的类型,统一成整型即 i 类型。如下图两个箭头的交汇处的绿色表格列所示。
那么,c(3) 类型的变量 '0.4', 如何将其转换成整型值呢?ABAP 帮助文档里也定义了清晰的转换规则,即 Conversion Rule.
转换的数据源,Source Field 是 c(3) 即 Character 类型,转换的目标类型为 int 即数值类型 Numeric Type.
根据源和目标字段,查看 ABAP 帮助文档对应的 Conversion Rule 区域,里面有一句话:
Decimal places are rounded commercially to integer values.
意思是,'0.4' 里包含的小数数位,会四舍五入,转换成整数值。
因此,字符型字面量 '0.4' 里的小数部分 0.4, 四舍五入等于 0. 因此 0 = '0.4' 的比较结果为 true.
类似的逻辑,1 = '0.51' 成立,0 = '0.51' 不成立。
除了使用 ABAP 帮助文档进行分析之外,我们还可以通过观察 ABAP 运行时的行为来判断。
大家觉得下面这段代码,会打印 true 还是 false?
IF 0 = '0.A'.
WRITE:/ 'true'.
ELSE.
WRITE:/ 'false'.
ENDIF.
答案是两个都不对,直接报运行时错误:
Unable to interpret "0.A" as a number.
显然,ABAP 运行时试图将 '0.A' 转换成一个 number,在转换过程中发生了 CONVT_NO_NUMBER 的运行时错误。
本例里这种 '0.4' 悄悄转换成 0 的行为,其实就是编程语言里的隐式类型转换。
隐式类型转换,也被称为自动类型转换,指的是编程语言里当一个表达式,包含了不同类型的操作数时,编译器或解释器自动地将其中一个或多个操作数转换为兼容的类型,以确保整个表达式能够顺利执行。
简而言之,当存在不同类型的值参与同一个操作时,编程语言自动进行类型调整以适应操作的需求。
比如下面的 JavaScript 代码,输出 510.
let num = 5;
let result = num + "10";
console.log(result);
变量 num 是一个整数,而 "10" 是一个字符串。当我们尝试将它们相加时,JavaScript 并不会抛出错误。相反,它会将整数 5 隐式转换为字符串,并执行字符串连接操作,输出结果为 "510"。这个转换过程完全是由 JavaScript 自动完成的,程序员不需要显式地进行类型转换。
隐式类型转换一方面能给开发工作带来便利。但另一方面,因为其隐式特性,有时发生在后台的转换逻辑,并不是开发人员期望中的行为。
笔者曾经就在工作中,处理过一个隐式类型转换被开发人员忽略而导致的软件故障。
详情请参阅笔者之前的文章:
关于 SAP ABAP 字符变量和字符串变量字符个数的一个知识点,和一个血案
也欢迎大家加入我的知识星球,共同交流 SAP 业务和技术知识。