5

默认情况下,包含 AF 数字的十六进制文字将转换为 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 中测试

4

2 回答 2

6

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

前:

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
于 2018-02-22T12:02:26.067 回答
4

Recall that in Scala we can easily define new ways to interpret arbitrary String literals by adding methods to a special class StringContext using the "pimp-my-library"-pattern. For example, we can add the method b for creating single bytes to StringContext so that we can write down bytes as follows:

val myByte = b"5C"

Here is how it can be implemented:

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
   }
}

In order to use this new syntax, we have to import the above object into implicit scope. Then we can do this:

/* Examples */ {

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

  printByte(b"01")
  printByte(b"7F")
  printByte(b"FF")
  printByte(b"80")
}

This will print:

01
7F
FF
80

You can obviously tweak the implementation (e.g. you can rename "b" to "hex" or "x" or "Ox" or something like this).


Note that this technique can be easily extended to deal with entire byte arrays, as described in this answer to a similar question. This would allow you to write down byte arrays without repeating the annoying 0x-prefix, e.g.:

val myBytes = hexBytes"AB,CD,5E,7F,5A,8C,80,BC"
于 2018-02-22T13:20:53.203 回答