Встроенные в стандартную библиотеку Scala двоичные цифры String
форматеры (toBinaryString
) для целочисленных типов (Byte
, Short
, Char
, Int
и Long
)очень ограничены.И реализация для Boolean
не предусмотрена.
Кроме того, для Byte
и Short
фактический выданный формат неверен для отрицательных значений (так как оба варианта реализации Int.toBinaryString
, которые затем1
заполняет до 32 символов, а не правильной ширины 8 и 16 символов соответственно.
Кроме того, я прочитал каждый ответ здесь.И я довольно много узнал о различных подходах к решению этой проблемы.В конечном счете, не было ни капли в решении, которое «просто работало» в моем текущем проекте.Итак ...
Я создал единую реализацию метода, исправляя, а затем исправляя все вышеперечисленные несоответствия, ошибки и добавляя недостающие функциональные возможности.Теперь, если бы я только мог понять, как включить это в стандартную библиотеку для 2.13 и Scala 3 ...
Параметр size
имеет три области значений.Более подробные сведения см. В комментариях к коду.
size = 0
-> (ПО УМОЛЧАНИЮ) заполнение нулями до размера в битах содержащего типа size < 0
-> модель по умолчаниюповедение функции toBinaryString уже на Byte
, Short
, Char
, Int
и Long
- также исправьте скрытое повышение в Int
для Byte
и Short
size > 0
-> вызывающий абонент обозначен нулевой заливкой - игнорируется, если размер меньше, чем длина, необходимая для захвата цифры 1
непосредственно слева от самой левой цифры 0
(для сохранения знака)
def toBinaryString[A <: AnyVal](value: A, size: Int = 0): String = {
val zerosX64: String = //maximum possible number of leading zeros
"0" * 64
val (valueAsBinaryString, typeSize) =
value match {
case valueAlmostTyped: Boolean =>
(if (valueAlmostTyped) "1" else "0", 1)
case valueAlmostTyped: Byte =>
(valueAlmostTyped.toByte.toBinaryString.takeRight(8), 8) //take() fixes hidden upcast to Int in Byte.toBinaryString
case valueAlmostTyped: Short =>
(valueAlmostTyped.toShort.toBinaryString.takeRight(16), 16) //take() fixes hidden upcast to Int in Short.toBinaryString
case valueAlmostTyped: Char =>
(valueAlmostTyped.toChar.toBinaryString, 16)
case valueAlmostTyped: Int =>
(valueAlmostTyped.toInt.toBinaryString, 32)
case valueAlmostTyped: Long =>
(valueAlmostTyped.toLong.toBinaryString, 64)
case _ =>
throw new IllegalArgumentException(s"toBinaryString not implemented for this type [${value.getClass.getSimpleName}] - only implemented for Boolean, Byte, Short, Char, Int, and Long")
}
val newSize =
if (size < 0) //model and fix the behavior of existing toBinaryString function on Byte, Short, Char, Int, and Long, and add for Binary
valueAsBinaryString.length
else
if (size == 0) //zero fill to the bit size of the containing type
typeSize
else
if (valueAsBinaryString.length > size) //possibly override the caller specified custom size value as it is smaller than the resulting valueAsBinaryString itself
if (valueAsBinaryString.take(valueAsBinaryString.length - size + 1).exists(_ == '0')) //only override if there isn't a zero dropped (which includes protecting the sign by ensuring if all 1s preceded the 0, at least a single one is preserved
valueAsBinaryString.length
else //caller specified custom value
size
else //caller specified custom value
size
( (
if (newSize > valueAsBinaryString.length)
zerosX64.take(newSize - valueAsBinaryString.length)
else
""
)
+ valueAsBinaryString.takeRight(newSize)
)
}