我有一个需要输入并返回输出的服务:
hits.total
输入始终是observable发出的前一个元素,服务调用的输出应该是observable发出的下一个元素。并且应该重复此序列,直到某个项目满足某个条件。
实际上,我有一棵树的叶子,我把叶子送到一个服务,告诉我它的父母是什么。我继续这样做,直到我到达根。
我的第一个解决方案:
我递归调用flatMap函数。由于递归,我不喜欢这个解决方案:
Item callService(Item input);
我的第二个解决方案:
我维护一个外部队列,基本上我用此队列提供observable。仍然看起来不太好。
Observable.just(Item.of("start"))
.map(Result::of)
.flatMap(App::fallbackUntilIsRoot)
.blockingSingle();
private static Observable<Result> fallbackUntilIsRoot(Result previousResult)
{
if (previousResult.isRoot())
{
return Observable.just(previousResult);
} else
{
return Service.call(previousResult.getItem())
.flatMap(App::fallbackUntilIsRoot); // recursion
}
}
是否有Rx方式进行此类链接?
答案 0 :(得分:1)
与此同时,我找到了我的问题的名称。它叫做corecursion。 RxJava 2有一个干净的(无副作用)解决方案来解决这个问题。
private static void solutionWithGenerate()
{
Result startElement = Result.of(Item.of("start"));
Result result = Observable.generate(() -> startElement, App::generate)
.startWith(startElement)
.lastElement()
.blockingGet();
System.out.println(result);
}
private static Result generate(Result previousResult, Emitter<Result> emitter)
{
Result newResult = Service.callDirectly(previousResult.getItem());
if (newResult.isEmpty())
{
emitter.onComplete();
} else
{
emitter.onNext(newResult);
}
return newResult;
}
也可以在RxJava 1中完成。更冗长一点: Observable.Generate in RxJava?
答案 1 :(得分:0)
你可以通过保留当前迭代项目的单个副作用字段来实现
将repeat()
与takeUntil()
组合在一起会使while循环与fromCallable()
一起使循环中的迭代器变为可变(即使用just()
将永远重复初始值):
it = Result.of(Item.of("start"));
Observable.fromCallable(() -> it)
.map(result -> {
it = service.call(result);
return result;
})
.repeat()
.takeUntil(Item -> it.isRoot())
.subscribe(item -> .....);