2015-03-14 3 views
1

У меня есть последовательность элементов, в частности байтов, которые я хотел бы совместить с чем-то более высоким уровнем, например. 16-разрядные целые числа. Наивный подход будет выглядеть следующим образом:, соответствующий нескольким элементам из последовательности элементов

val stream: Seq[Byte] = ??? 
def short(b1: Byte, b0: Byte): Short = ??? 

stream match { 
    case Seq(a1, a0, b1, b0, _*) => (short(a1, a0), short(b1, b0)) 
    // ... 
} 

Что мне удалось сделать что-то вроде этого, используя object short_:: с unapply способом:

stream match { 
    case a short_:: b short_:: _ => (a, b) 
    // ... 
} 

Однако, я не могу сказать, что я люблю синтаксис здесь, потому что он не очень похож на регулярное сопоставление шаблонов. Я бы счастливее, чтобы написать что-то вроде этого:

stream match { 
    case Short(a) :: Short(b) :: _ => (a, b) 
    // ... 
} 

Конечно, с помощью идентификаторов Short и ::, вероятно, трудно/плохая идея, но я думаю, что он получает точку в поперечнике для целей данного вопроса.

Возможно ли написать собственный код соответствия шаблону, который создает синтаксис, подобный этому? Я ограничиваю себя содержимым с фиксированной шириной потока здесь (хотя и не одной ширины: например, Short и Int должны быть возможны), но мне нужно иметь возможность сопоставлять оставшуюся часть потока, например :: tail или Seq(..., tail @ _*).

+0

Ну, мне кажется, что ваш первый подход не наивен. Напротив, это вполне может быть одним из естественных способов достичь этого. –

ответ

2

Попробовать это

object ::: { 
    def unapply(seq: Seq[Byte]): Option[(Int, Seq[Byte])] = { 
    if(seq.size > 1) Some(seq(0) * 256 + seq(1), seq.drop(2)) 
    else None 
    } 
} 


val list = List[Byte](1,2,3,4,5,6,7,8) 
list match { 
    case a ::: b ::: rest => println(a + ", " + b + ", " + rest) 
} 

вы можете также смешать байт, шорты и Интс.

object +: { 
    def unapply(seq: Seq[Byte]): Option[(Byte, Seq[Byte])] = { 
    if(seq.size > 0) Some(seq.head, seq.tail) 
    else None 
    } 
} 

object ++: { 
    def unapply(seq: Seq[Byte]): Option[(Short, Seq[Byte])] = seq match { 
    case a +: b +: rest => Some(((a&0xFF) << 8 | (b&0xFF)).toShort, rest) 
    case _ => None 
    } 
} 

object +++: { 
    def unapply(seq: Seq[Byte]): Option[(Int, Seq[Byte])] = seq match { 
    case a ++: b ++: rest => Some((a&0xFFFF) << 16 | (b&0xFFFF), rest) 
    case _ => None 
    } 
} 

val list = List[Byte](1,2,3,4,5,6,7,8,9,10,11,12) 
list match { 
    case a +: b ++: C+++: rest => println(a + ", " + b + ", " + c + ", " + rest) 
} 

+: означает, что переменная слева байт, ++: означает, что переменная слева короткая и +++: означает междунар. Кстати. по какой-то причине это работает, только если имена объектов заканчиваются на «:».

+0

Это то, что у меня уже есть, см. Строку над моим вторым кодовым списком: «Что мне удалось сделать ...» –

+0

Кстати, при использовании синтаксиса операторского стиля методы - и для сопоставления шаблонов - имена объектов - что конец в двоеточии является право-ассоциативным (и этот «этот» объект является правильным операндом для вызовов методов). для других имен вам нужно добавить круглые скобки, что является уродливым, следовательно, исключение из нормальной ассоциативности;) –

+0

«+: означает, что переменная слева - это байт, ++: означает, что переменная слева является короткой и +++: означает int. ". ЮК. Первые два уже имеют другие (противоречивые) значения в качестве операторов ... –

Смежные вопросы