Ответ 1
Я использовал библиотеку sbinary, и это очень приятно. Документация немного редка, но я бы предложил сначала посмотреть на старую страницу wiki, поскольку это дает вам отправную точку. Затем проверьте спецификации теста, так как это дает вам несколько хороших примеров.
Основное преимущество sbinary заключается в том, что он дает вам способ описать формат проводов для каждого объекта в качестве объекта Format. Затем вы можете инкапсулировать эти форматированные типы в объект формата более высокого уровня, а Scala выполняет весь тяжелый подъем этого типа до тех пор, пока вы включили его в текущую область как неявный объект.
Как я уже сказал ниже, теперь я рекомендую использовать scodec вместо sbinary. В качестве примера использования scodec я буду реализовывать, как читать двоичное представление в памяти следующей C struct:
struct ST
{
long long ll; // @ 0
int i; // @ 8
short s; // @ 12
char ch1; // @ 14
char ch2; // @ 15
} ST;
Соответствующий класс case Scala:
case class ST(ll: Long, i: Int, s: Short, ch1: String, ch2: String)
Я делаю вещи немного легче для себя, просто говоря, что мы храним Strings вместо Chars, и я скажу, что они являются символами UTF-8 в структуре. Я также не имею дело с деталями endian или фактическим размером длинного и int-типа в этой архитектуре и просто предполагаю, что они равны соответственно 64 и 32.
Анализаторы Scodec обычно используют комбинаторы для создания парсеров более высокого уровня с более низких уровней. Итак, ниже мы определим синтаксический анализатор, который объединяет 8-байтовое значение, значение 4 байта, значение 2 байта, значение 1 байт и еще одно значение в 1 байт. Возврат этой комбинации является кодеком Tuple:
val myCodec: Codec[Long ~ Int ~ Short ~ String ~ String] =
int64 ~ int32 ~ short16 ~ fixedSizeBits(8L, utf8) ~ fixedSizeBits(8L, utf8)
Затем мы можем преобразовать это в класс case ST, вызвав на нем функцию xmap
, которая принимает две функции: одну, чтобы превратить кодек Tuple в тип назначения и другую функцию, чтобы взять тип назначения и превратить его в Форма кортежа:
val stCodec: Codec[ST] = myCodec.xmap[ST]({case ll ~ i ~ s ~ ch1 ~ ch2 => ST(ll, i, s, ch1, ch2)}, st => st.ll ~ st.i ~ st.s ~ st.ch1 ~ st.ch2)
Теперь вы можете использовать кодек так:
stCodec.encode(ST(1L, 2, 3.shortValue, "H", "I"))
res0: scodec.Attempt[scodec.bits.BitVector] = Successful(BitVector(128 bits, 0x00000000000000010000000200034849))
res0.flatMap(stCodec.decode)
=> res1: scodec.Attempt[scodec.DecodeResult[ST]] = Successful(DecodeResult(ST(1,2,3,H,I),BitVector(empty)))
Я бы посоветовал вам взглянуть на Scaladocs, а не на Руководство, так как в Scaladocs гораздо больше деталей. Руководство - это хорошее начало в самых основах, но оно не входит в состав композиции, но Scaladocs довольно хорошо обходятся.