为什么Kotlin/JS的===返回结果与Kotlin/JVM不同?

9

鉴于以下代码:

val value = "something"

println(value.toUpperCase().toLowerCase() == value)   // prints true
println(value.toUpperCase().toLowerCase() === value)  // prints false

在 Kotlin/JVM 1.3.40 上,我得到了以下结果:
true
false

在Kotlin/JS 1.3.40上,我得到了:
true
true

我希望两者都能得到相同的结果,并且我期望Kotlin/JVM的总体结果会有所不同(因为我应该有不同的String对象)。

为什么我的运行环境不同,结果也不同呢?

2个回答

4
这是因为运行时的处理方式不同。
在JVM中,==equals相对应,=====(标识检查)相对应,详见此处。同时,JavaScript的equals操作符更奇怪。如果你反编译你的代码,你会得到JS的这个:
kotlin.kotlin.io.output.flush();
if (typeof kotlin === 'undefined') { 
    throw new Error("Error loading module 'moduleId'. Its dependency 'kotlin' was not found. Please, check whether 'kotlin' is loaded prior to 'moduleId'."); 
}
var moduleId = function (_, Kotlin) { 
    'use strict'; 
    var equals = Kotlin.equals; 
    var println = Kotlin.kotlin.io.println_s8jyv4$; 
    function main(args) { 
        var value = 'something';
        println(equals(value.toUpperCase().toLowerCase(), value)); // NOTE: equals
        println(value.toUpperCase().toLowerCase() === value);      // NOTE: ===
    } 
    _.main_kand9s$ = main; 
    main([]); 
    Kotlin.defineModule('moduleId', _); 
    return _; 
}(typeof moduleId === 'undefined' ? {} : moduleId, kotlin); 
kotlin.kotlin.io.output.buffer;

现在,如果您考虑等效的Java代码(稍微缩短且没有Kotlin):

public static void main(String[] args){
    String value = "something";

    System.out.println(value.toUpperCase().toLowerCase().equals(value));
    System.out.println(value.toUpperCase().toLowerCase() == value);
}

toUpperCase().toLowerCase() 方法会创建一个新的对象,这将打破 == 比较,因为它是身份检查

虽然 === 也被概述为身份检查,但是a === b 是如果 a 和 b 是包含相同字符的字符串,则为 true 。从反编译的 Kotlin 代码可以看出,Kotlin.JS 编译为原始字符串而不是字符串对象。因此,在处理原始字符串时,JS 中的 === 将返回 true。


这是否构成Kotlin/JS实现中的一个bug?根据Kotlin语言参考,“引用相等性由===操作(及其否定对应物!==)检查。当且仅当a和b指向同一对象时,a === b的结果为true。 对于在运行时表示为原始类型的值(例如Int),===相等性检查等同于==检查。”(https://kotlinlang.org/docs/reference/equality.html#referential-equality)据我所知,字符串不是由原始类型表示的(https://kotlinlang.org/docs/reference/basic-types.html)。 - LarsH
@LarsH 或许是吧。老实说我不太确定,因为我不知道它是否打算支持底层本地运算符的差异。我建议您在Kotlin问题跟踪器上打开一个问题。如果这不是一个错误,至少我们可以清楚它是按设计还是不是。 - Zoe stands with Ukraine
也许@OP应该提交一个错误报告。 :-) - LarsH
@LarsH 但在 Kotlin/JS 中它们是这样的。 - Alexey Romanov
@Alexey 你的意思是,在 Kotlin/JS (1.3.40) 中,字符串是由原始类型表示的吗?是的,我认为我们已经达成了共识。 - LarsH

2
在JavaScript中,既有原始字符串,也有字符串对象(请参见例如https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String的“区分字符串原始值和字符串对象”)。在Kotlin / JS中,value.toUpperCase().toLowerCase() === value编译为JavaScript的value.toUpperCase().toLowerCase() === value(您可以通过查看https://try.kotlinlang.org/上的“生成的JavaScript代码”选项卡进行验证)。value.toUpperCase().toLowerCase()返回一个原始字符串。原始字符串上的===表示普通相等性。最初的回答。

2
"它在纯JavaScript中能够实现,我希望Kotlin/JS也能编译到它。但是,Kotlin的转换器难道不应该生成与Kotlin/JVM一样的结果吗?如果像对象相等这样的操作在不同平台上有所不同,我们如何编写Kotlin/Multiplatform项目呢?" - CommonsWare
1
对我来说,对象的相等性应该是你期望在不同平台上有所不同的东西。 - Alexey Romanov
2
@Alexey 如果 Kotlin 语言定义规定了特定的行为,不管是哪个平台,我们都不应该期望该行为在不同平台上有所不同。 - LarsH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接