【问题标题】:Why Does Kotlin/JS Return Different Results for === Than Does Kotlin/JVM?为什么 Kotlin/JS 为 === 返回与 Kotlin/JVM 不同的结果?
【发布时间】:2019-07-01 11:55:28
【问题描述】:

鉴于此代码:

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 对象)。

为什么我会根据运行时环境得到不同的结果?

【问题讨论】:

    标签: kotlin kotlin-js


    【解决方案1】:

    这是因为运行时处理它的方式。

    在 JVM 上,== 映射到 equals=== 映射到 ==(身份检查),如 here 所述。同时,JavaScript 的equals operators are weirder。如果你反编译你的代码,你会用 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() 创建一个新对象,它打破了== 比较,即is identity checking

    === 也被概述为身份检查,a === b is true if a and b are strings that contain the same characters。从反编译的 Kotlin 代码中可以看出,Kotlin.JS 编译为原始字符串,而不是字符串对象。因此,当您处理原始字符串时,JS 中的 === 将返回 true。

    【讨论】:

    • 这是否构成 Kotlin/JS 实现中的错误?根据 Kotlin lang ref,“引用相等性由 === 操作(及其否定的对应物!==)检查。a === b 当且仅当 a 和 b 指向相同时才计算为 true 对于在运行时表示为基本类型的值(例如,Int),=== 相等检查等同于 == 检查。” (kotlinlang.org/docs/reference/…) AFAICT,字符串不是由原始类型表示的 (kotlinlang.org/docs/reference/basic-types.html)。
    • @LarsH 也许吧。我不完全确定 tbh,因为我不确定它是否旨在支持某些运营商的底层原生差异的差异。我建议你在Kotlin issue tracker 上打开一个问题。如果它不是错误,我们至少会弄清楚它是否是设计使然。
    • 也许@OP 应该打开一个错误报告。 :-)
    • @LarsH 但在 Kotlin/JS 中它们是。
    • @Alexey 你的意思是,在 Kotlin/JS (1.3.40) 中,字符串是由原始类型表示的吗?是的,我认为我们对此达成了一致。
    【解决方案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() 返回一个原始字符串。 === 在原始字符串上是正常的相等。

    【讨论】:

    • “它在纯 JavaScript 中运行,我希望 Kotlin/JS 编译到它”——但 Kotlin 的转译器不应该生成与 Kotlin/JVM 相同的纯 Kotlin 操作结果的代码?如果对象相等等内容因平台而异,我们如何编写 Kotlin/Multiplatform 项目?
    • 对我来说,对象相等性正是您应该期望因平台而异。
    • @Alexey 如果 Kotlin 语言定义指定了某些行为而与平台无关,我们不应期望指定的行为因平台而异。
    猜你喜欢
    • 1970-01-01
    • 2021-09-07
    • 2023-01-27
    • 2013-10-01
    • 1970-01-01
    • 2012-07-28
    • 2013-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多