Показать сообщение отдельно
Старый 13.02.2017, 08:31   #10
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений
(для 886 пользователей)
Ответ: Полезные находки

Массивы в шаблонных типах в Java.

Интро. Я глядя на RxJava решил сделать некое подобие, но попроще.
Полученную штуку назвал CallChain - это цепочки вызовов методов.
Суть: составляем последовательность операций в цепочку "операторов", на вход очередного оператора подаётся выход из предыдущего.
Профит - удобно составлять логику, ошибки всегда прокидываются до получателя, можно остановить выполнение на любом этапе.
(я это сделал в виде worker - operator(s) - receiver (операторы обычно тоже worker'ы).

Кароче, суть "проблемы" открылась при добавлении оператора, который бы превратил массив в последовательность единичных элементов (flatMap).

Оператор наследуется от базового Chunk<TIn,TOut>{ ... }
т.е. у него есть тип входных данных и тип выходных.
Прицепляемый к нему оператор должен на вход получить выход от текущего, а на выходе может иметь любой тип, т.е. Chunk<TOut,TOut2>

Так вот, как из шаблонных типов вытащить массив?

Я не долго думая написал для нашего flatMap'а такой вариант:
Chunk<TOut[],TOut>
В надежде, что если мы на вход даём Integer[], то TOut распознается как Integer.

И это так, но только в рамках самого класса!

В каждом операторе есть входной метод
void onReceive<TIn data>{ ... }
в рамках этого метода по описанному выше типу данных я смог нормально пробежать по массиву:
void onReceive<TOut data>{ // здесь TOut, т.к. на вход берём быход от предыдущего оператора
  for (TOut i : data){
    sendResult(i); // пересылаем каждое значение в nextChunk
  }
}
Всё хорошо, тут наш Integer.

Однако, когда к этому оператору хотим прицепить следующий, у которого на входе должен быть штучный Integer,
то получаем ошибку нестыковки типов - "на входе ожидается массив Integer[]".

Т.е. наш TOut вне самого класса оператора расползнаётся как массив.
Но тогда логично, что конструкция <TOut[],TOut> должна развернуться в <Integer[][],Integer[]> внутри класса, но этого не происходит.
И это немного сломало мне мозг.
^ Ради этой инфы и написан этот пост.

В итоге я добавил шаблонный тип TOut2 к этому оператору
public <TOut2> Chunk<TOut,TOut2> flatMap() { ... }
и убрал признак массива в шаблонном типе TOut
(проверка на массив или итератор делается через instanceof;
не фэншуй? зато работает, и я пока на экспорт не планирую отдавать, а мне норм такой вариант).

при использовании теперь нужно явно указывать тип
new CallChain()
  .someWorker()
  .<Integer>flatMap()
  .someOperator()
  .....
чуток неудобно, но я лучшего решения не придумал.

кому интересен весь код - гитхаб.

Да, я смотрел исходники RxJava, но нихрена не понял, умеют же люди писать такие заморочки.

Последний раз редактировалось Жека, 20.02.2017 в 10:12.
(Offline)
 
Ответить с цитированием