Kotlin 学习笔记之 Kotlin 的 BUG —— Long 的隐藏坑

Long 数据类型占用内存空间 2^64,即可以表示-2^63 ~ 2^63-1 的整型数字。

代码:

fun main(args: Array<String>) {
    println(Long.MIN_VALUE)
    println(Long.MAX_VALUE)
//    val lT: Long = -9223372036854775808L //64位 -9223372036854775808~9223372036854775807
}

打印:

-9223372036854775808
9223372036854775807

但是,直接写就完蛋了:

fun main(args: Array<String>) {
    println(Long.MIN_VALUE)
    println(Long.MAX_VALUE)
    val lT: Long = -9223372036854775808L //64位 -9223372036854775808~9223372036854775807
}

提示超出了区间范围。

这里写图片描述

可以看到,Long最大值是正常的。但是最小值赋值时,语法检测异常了?这是IntelliJ IDEA 的 bug?

Dmitry Jemerov 告诉我,- 在kotlin中,被注册为减号,而不是常量的一部分。
所以 -9223372036854775808L 的减号是被忽略的,于是 9223372036854775808 > Long.MAX_VALUE,导致了判断失误。

但是,问题又来了。如果 - 不是常量的一部分,那为什么,换成 Int 却又可以?

val minI: Int = -2147483648 //Int.MIN_VALUE

IDEA 是不会报错的。

Look here:

这里写图片描述

这就奇了怪了。

坑乎?

于是,我将问题挂到了stackoverflow:

https://stackoverflow.com/questions/46422969/why-kotlin-wrong-val-mint-long-9223372036854775808l-long-min-value

歪果仁大神给的答案是:

I'm not sure I 100% understand your question - did you expect val minI: Int = -2147483648 to raise an error, as well? – Frank Schmitt
Note: in kotlin-stdlib, this constant is defined as public const val MIN_VALUE: Long = -9223372036854775807L - 1L (you can navigate to declaration of Long.MIN_VALUE).

他说这是由于Long的构造函数里对Long的最小值的定义导致的,于是我翻开Long的源代码,看到:

/**
* A constant holding the minimum value an instance of Long can have.
*/
public const val MIN_VALUE: Long = -9223372036854775807L - 1L

没办法了,不能显式使用 val m: Long = -9223372036854775808L ` 。以最小值来显式赋值是行不通的。

这应该是语言设计的问题。这个问题实际上在2012年就被歪果仁发现了,歪果仁发给我的链接:

https://youtrack.jetbrains.com/issue/KT-2780

当时提出的问题的是:
Kotlin does not seem to natively support negative values, but rather treats a negative as -(positive). This is problematic in many situations. Handling of negative hex literals should also be improved.

Example code

fun negativeLiteralsIssue() {
    // Negative bytes not supported

    val b1: Byte = 127 // works
    val b2: Byte = -1 // error, treated as 1.minus() : Int
    val b3: Byte = -128 // error, treated as 128.minus() : Int
    val b4: Byte = -128.toByte() // works, compiles to -(byte)128
    val b5: Byte = (-128).toByte() // works, compiles to (byte)(-128)

    // Similar for shorts

    val s1: Short = 32767
    val s2: Short = -1 // error
    val s3: Short = -32768 // error
    val s4: Short = -32768.toShort()
    val s5: Short = (-32768).toShort()

    // ints have trouble with Integer.MIN_VALUE

    val i1: Int = 2147483647 // works
    val i2: Int = -1 // works
    val i3: Int = -2147483647 // works
    val i4: Int = -2147483648 // error, treated as 2147483648.minus() : Long
    val i5: Int = -2147483648.toInt() // works, compiles to -(int)0x80000000L
    val i6: Int = (-2147483648).toInt() // works, compiles to (int)(-0x80000000L)

    // longs, no way to use the Long.MIN_VALUE literal

    val l1: Long = 9223372036854775807
    val l2: Long = -1 // error, treated as 1.minus() : Int
    val l3: Long = -9223372036854775807 // works
    val l4: Long = -9223372036854775808 // error
    val l5: Long = -9223372036854775808.toLong() // error, out of range
    val l6: Long = (-9223372036854775808).toLong() // error, out of range
    assertEquals(java.lang.Long.MIN_VALUE, -9223372036854775807 - 1) // ok

    // All types have trouble with negative hex literals.

    val hb0: Byte = 0x7F // works
    val hb1: Byte = 0x80 // error
    val hb2: Byte = 0xFF // error
    val hb3: Byte = 0x80.toByte() // works
    val hb4: Byte = 0xFF.toByte() // works

    val hs0: Short = 0x7FFF // works
    val hs1: Short = 0x8000 // error
    val hs2: Short = 0xFFFF // error
    val hs3: Short = 0x8000.toShort() // works
    val hs4: Short = 0xFFFF.toShort() // works

    val hi0: Int = 0x7FFFFFFF // works
    val hi1: Int = 0x80000000 // error
    val hi2: Int = 0xFFFFFFFF // error
    val hi3: Int = 0x80000000.toInt() // works
    val hi4: Int = 0xFFFFFFFF.toInt() // works

    // For long especially, there's no way to use negative hex literals

    val hl0: Long = 0x7FFFFFFFFFFFFFFF // works
    val hl1: Long = 0x8000000000000000 // error
    val hl2: Long = 0xFFFFFFFFFFFFFFFF // error
    val hl3: Long = 0x8000000000000000.toLong() // error
    val hl4: Long = 0xFFFFFFFFFFFFFFFF.toLong() // error
    val hl5: Long = (java.lang.Long.parseLong("80000000", 16) shl 32) or java.lang.Long.parseLong("00000000", 16)
    val hl6: Long = (java.lang.Long.parseLong("FFFFFFFF", 16) shl 32) or java.lang.Long.parseLong("FFFFFFFF", 16)
    assertEquals(java.lang.Long.MIN_VALUE, hl5) // ok
    assertEquals(-1.toLong(), hl6) //ok
}

虽然提出了很久了。但我想,未来这个问题都不会做出改变了。而且此问题被提示为过时了。

——end

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值