Массивы в шаблонных типах в 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, но нихрена не понял, умеют же люди писать такие заморочки.