在Scala中,我可以用这种方式声明一个字节数组
val ipaddr: Array[Byte] = Array(192.toByte, 168.toByte, 1.toByte, 9.toByte)
这太冗长了。是否有更简单的方法来声明Byte数组,类似于Java的
byte[] ipaddr = {192, 168, 1, 1};
请注意,由于String
中的.
,以下内容会导致错误
InetAddress.getByAddress("192.168.1.1".toByte)
答案 0 :(得分:39)
我相信你能做的最短的就是
val ipaddr = Array[Byte](192.toByte, 168.toByte, 1, 9)
你必须将192
和168
转换为字节,因为它们不是有效的字节文字,因为它们超出了有符号字节的范围([-128,127] )。
请注意,Java也是如此,以下是编译错误:
byte[] ipaddr = {192, 168, 1, 1};
您必须将192和168转换为字节:
byte[] ipaddr = {(byte)192, (byte)168, 1, 1};
答案 1 :(得分:37)
Array(192, 168, 1, 1).map(_.toByte)
怎么样?
答案 2 :(得分:9)
要扩展 Chris Martin的答案,如果您感到懒惰,并且想要一次又一次地输入Array(...).map(_.toByte)
,你总是可以编写一个可变函数:
def toBytes(xs: Int*) = xs.map(_.toByte).toArray
现在,您可以像在Java中一样简洁地声明您的字节数组:
val bytes = toBytes(192, 168, 1, 1) // Array[Byte](-64, -88, 1, 1)
答案 3 :(得分:3)
您可以使用隐式
implicit def int2byte(int: Int) = { int.toByte }
这将在需要byte的位置转换范围内的所有Int值。
答案 4 :(得分:3)
通过向StringContext
添加方法,可以轻松定义将字符串文字转换为字节数组的各种方法。例如,我们可以这样做:
val bytes = hexdump"742d 6761 2e00 6f6e 6574 672e 756e 622e"
或者这个:
Array(0xAB, 0xCD, 0xEF).map(_.toByte)
请注意,它对于以十六进制表示法处理字节数组特别有用,因为在每个字节前面写出“0x”前缀会很快变得非常烦人,如in this example所示。当在map
中使用十六进制表示法时,对implicit class
的调用不是尴尬,而是重复的“0x” - 前缀会产生所有噪声。
这是一个小代码片段,通过提供包裹StringContext
的{{1}}来说明如何实现字节数组创建的几种不同方式:
implicit class ByteContext(private val sc: StringContext) {
/** Shortcut to the list of parts passed as separate
* string pieces.
*/
private val parts: List[String] = sc.parts.toList
/** Parses an array of bytes from the input of a `StringContext`.
*
* Applies `preprocess` and `separate` and finally `parseByte`
* to every string part.
* Applies `parseByte` to every vararg and interleaves the
* resulting bytes with the bytes from the string parts.
*
* @param preprocess a string preprocessing step applied to every string part
* @param separate a way to separate a preprocessed string part into substrings for individual bytes
* @param parseByte function used to parse a byte from a string
* @param args varargs passed to the `StringContext`
* @return parsed byte array
*
* Uses a mutable `ListBuffer` internally to accumulate
* the results.
*/
private def parseBytes(
preprocess: String => String,
separate: String => Array[String],
parseByte: String => Byte
)(args: Any*): Array[Byte] = {
import scala.collection.mutable.ListBuffer
val buf = ListBuffer.empty[Byte]
def partToBytes(part: String): Unit = {
val preprocessed = preprocess(part)
if (!preprocessed.isEmpty) {
separate(preprocessed).foreach(s => buf += parseByte(s))
}
}
// parse all arguments, convert them to bytes,
// interleave them with the string-parts
for ((strPart, arg) <- parts.init.zip(args)) {
partToBytes(strPart)
val argAsByte = arg match {
case i: Int => i.toByte
case s: Short => s.toByte
case l: Long => l.toByte
case b: Byte => b
case c: Char => c.toByte
case str: String => parseByte(str)
case sthElse => throw new IllegalArgumentException(
s"Failed to parse byte array, could not convert argument to byte: '$sthElse'"
)
}
buf += argAsByte
}
// add bytes from the last part
partToBytes(parts.last)
buf.toArray
}
/** Parses comma-separated bytes in hexadecimal format (without 0x-prefix),
* e.g. "7F,80,AB,CD".
*/
def hexBytes(args: Any*): Array[Byte] = parseBytes(
s => s.replaceAll("^,", "").replaceAll(",$", ""), // ,AB,CD, -> AB,CD
_.split(","),
s => Integer.parseInt(s, 16).toByte
)(args: _*)
/** Parses decimal unsigned bytes (0-255) separated by periods,
* e.g. "127.0.0.1".
*/
def ip(args: Any*): Array[Byte] = parseBytes(
s => s.replaceAll("^[.]", "").replaceAll("[.]$", ""), // .1.1. -> 1.1
_.split("[.]"),
s => Integer.parseInt(s, 10).toByte
)(args:_*)
/** Parses byte arrays from hexadecimal representation with possible
* spaces, expects each byte to be represented by exactly two characters,
* e.g.
* "742d 6761 2e00 6f6e 6574 672e 756e 622e".
*/
def hexdump(args: Any*): Array[Byte] = parseBytes(
s => s.replaceAll(" ", ""),
_.grouped(2).toArray,
s => Integer.parseInt(s, 16).toByte
)(args: _*)
/** Parses decimal unsigned bytes (0-255) separated by commas,
* e.g. "127.0.0.1".
*/
def decBytes(args: Any*): Array[Byte] = parseBytes(
s => s.replaceAll("^,", "").replaceAll(",$", ""), // ,127, -> 127
_.split(","),
s => Integer.parseInt(s, 10).toByte
)(args:_*)
}
只要此类处于隐式作用域,我们就可以使用以下所有表示法来定义字节数组:
def printBytes(bytes: Array[Byte]) =
println(bytes.map(b => "%02X".format(b)).mkString("[",",","]"))
// bunch of variables to be inserted in the strings
val a: Int = 192
val b: Long = 168L
val c: Byte = 1.toByte
val d: String = "0F"
val e: String = "15"
printBytes(ip"192.168.1.15")
printBytes(ip"192.$b.1.$e")
printBytes(ip"$a.$b.$c.$e")
printBytes(hexBytes"C0,A8,01,0F")
printBytes(hexBytes"C0,$b,$c,0F")
printBytes(hexBytes"$a,$b,$c,0F")
printBytes(decBytes"192,$b,1,15")
printBytes(decBytes"192,168,$c,$e")
printBytes(decBytes"$a,$b,1,$e")
printBytes(hexdump"C0A8 010F")
printBytes(hexdump"$a $b $c $d")
printBytes(hexdump"C0 $b 01 $d")
请注意,字符串文字还可以包含使用字符串内部$varargVar
语法的变量引用。所有示例都生成相同的字节数组[C0,A8,01,0F]
。
关于性能:以上所有都是围绕方法调用构建的,文字在编译时不会转换为字节数组。
答案 5 :(得分:2)
对于您的具体示例,您只需使用InetAddress.getByName
代替:
InetAddress.getByName("192.168.1.1")
一般来说迪迪埃是对的,Byte
是-128到127,所以这有效:
Array[Byte](1,2,3)
但这不是:
Array[Byte](192, 168, 1, 1)