【问题标题】:Scala hex literal for bytes用于字节的 Scala 十六进制文字
【发布时间】:2018-02-23 04:25:41
【问题描述】:

包含 A-F 数字的十六进制文字默认转换为 int。当我尝试使用 0x 清除 Int 时,它正在正确创建。

val a: Int = 0x34
val b: Int = 0xFF

但是当我试图用 0x 清除一个字节时,第二行没有编译

val a: Byte = 0x34
val b: Byte = 0xFF // compilation error

我找到了一种解决方法

val a: Byte = 0x34
val b: Byte = 0xFF.toByte

但是有没有任何体面的方法来清除一个字节的十六进制文字?

例如,我试图以这种方式在测试方法中清除字节数组

anObject.someMethod(1, 1.1f, 0xAB, "1") shouldBe
  Array[Byte](0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF)
anObject.someMethod(2, 2.2f, 0xCD, "2") shouldBe
  Array[Byte](0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE)
anObject.someMethod(3, 3.2f, 0xEF, "3") shouldBe
  Array[Byte](0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD)

但不是这样

anObject.someMethod(1, 1.1f, 0xAB.toByte, "1") shouldBe
  Array[Byte](0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte, 0xAF.toByte)
anObject.someMethod(2, 2.2f, 0xCD.toByte, "2") shouldBe
  Array[Byte](0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte, 0xBE.toByte)
anObject.someMethod(3, 3.2f, 0xEF.toByte, "3") shouldBe
  Array[Byte](0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte, 0xCD.toByte)

在 Scala 2.12.4 中测试

【问题讨论】:

标签: scala literals scala-2.12


【解决方案1】:

您可以通过隐式转换来做到这一点。

之前:

def f(b: Byte) = println(s"Byte = $b")
f(0x34)
f(0xFF) // compilation error

之后:

implicit def int2Byte(i: Int) = i.toByte

def f(b: Byte) = println(s"Byte = $b")
f(0x34)
f(0xFF)

输出:

Byte = 52
Byte = -1

【讨论】:

    【解决方案2】:

    回想一下,在 Scala 中,我们可以通过使用“pimp-my-library”模式向特殊类 StringContext 添加方法来轻松定义解释任意 String 文字的新方法。例如,我们可以将创建单个字节的方法b添加到StringContext,这样我们就可以将字节写成如下:

    val myByte = b"5C"
    

    这是如何实现的:

    implicit class SingleByteContext(private val sc: StringContext) {
       def b(args: Any*): Byte = {
         val parts = sc.parts.toList
         assert(
           parts.size == 1 && args.size == 0, 
           "Expected a string literal with exactly one part"
         )
         Integer.parseInt(parts(0), 16).toByte
       }
    }
    

    为了使用这种新语法,我们必须将上述对象导入隐式作用域。然后我们可以这样做:

    /* Examples */ {
    
      def printByte(b: Byte) = println("%02X".format(b))
    
      printByte(b"01")
      printByte(b"7F")
      printByte(b"FF")
      printByte(b"80")
    }
    

    这将打印:

    01
    7F
    FF
    80
    

    您显然可以调整实现(例如,您可以将“b”重命名为“hex”或“x” 或“Ox”或类似的东西)。


    请注意,该技术可以轻松扩展以处理整个字节数组,如in this answer to a similar question 所述。这将允许您写下字节数组而无需重复烦人的0x-前缀,例如:

    val myBytes = hexBytes"AB,CD,5E,7F,5A,8C,80,BC"
    

    【讨论】:

      猜你喜欢
      • 2017-09-13
      • 2015-08-08
      • 2014-03-08
      • 2012-01-24
      • 2011-01-30
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      相关资源
      最近更新 更多