字节的 Scala 十六进制文字

Naf*_*rar 5 scala literals scala-2.12

默认情况下,包含 AF 数字的十六进制文字将转换为 int。当我试图用0x声明一个 Int 时,它正在正确创建。

val a: Int = 0x34
val b: Int = 0xFF
Run Code Online (Sandbox Code Playgroud)

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

val a: Byte = 0x34
val b: Byte = 0xFF // compilation error
Run Code Online (Sandbox Code Playgroud)

我找到了一种解决方法

val a: Byte = 0x34
val b: Byte = 0xFF.toByte
Run Code Online (Sandbox Code Playgroud)

但是有没有什么像样的方法可以从十六进制文字中清除一个字节?

例如,我试图以这种方式在 Test 方法中清除 Byte 数组

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)
Run Code Online (Sandbox Code Playgroud)

但不是这样

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)
Run Code Online (Sandbox Code Playgroud)

在 Scala 2.12.4 中测试

Tom*_*Tom 6

您可以使用隐式转换来做到这一点。

前:

def f(b: Byte) = println(s"Byte = $b")
f(0x34)
f(0xFF) // compilation error
Run Code Online (Sandbox Code Playgroud)

后:

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

def f(b: Byte) = println(s"Byte = $b")
f(0x34)
f(0xFF)
Run Code Online (Sandbox Code Playgroud)

输出:

Byte = 52
Byte = -1
Run Code Online (Sandbox Code Playgroud)


And*_*kin 5

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

val myByte = b"5C"
Run Code Online (Sandbox Code Playgroud)

下面是它的实现方法:

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
   }
}
Run Code Online (Sandbox Code Playgroud)

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

/* Examples */ {

  def printByte(b: Byte) = println("%02X".format(b))

  printByte(b"01")
  printByte(b"7F")
  printByte(b"FF")
  printByte(b"80")
}
Run Code Online (Sandbox Code Playgroud)

这将打印:

01
7F
FF
80
Run Code Online (Sandbox Code Playgroud)

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


请注意,此技术可以轻松扩展以处理整个字节数组,如对类似问题的回答中所述。这将允许您写下字节数组,而无需重复烦人的0x- 前缀,例如:

val myBytes = hexBytes"AB,CD,5E,7F,5A,8C,80,BC"
Run Code Online (Sandbox Code Playgroud)