问题
Hex literal containing A-F digit are converting to int by default. When I am trying to declear an Int with 0x it is creating correctly.
val a: Int = 0x34
val b: Int = 0xFF
But when I am trying to declear a Byte with 0x second line is not compiling
val a: Byte = 0x34
val b: Byte = 0xFF // compilation error
I have found a workaround that is
val a: Byte = 0x34
val b: Byte = 0xFF.toByte
But is there any decent way to declear a Byte from its hex literal?
For example I am trying to declear a Byte array in a Test method in this way
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)
But not in this way
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)
Tested in scala 2.12.4
回答1:
You can do this with implicit conversions.
Before:
def f(b: Byte) = println(s"Byte = $b")
f(0x34)
f(0xFF) // compilation error
After:
implicit def int2Byte(i: Int) = i.toByte
def f(b: Byte) = println(s"Byte = $b")
f(0x34)
f(0xFF)
Output:
Byte = 52
Byte = -1
回答2:
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"
来源:https://stackoverflow.com/questions/48926339/scala-hex-literal-for-bytes