当我只能生成其他可观察值时,如何从起始可观察值生成可观察值?
我想生成一个可观察值,其中可观察值的每个值都依赖于它之前的值,从单个值开始。如果我在像 Func
这样的值之间进行简单的转换,那么使用 Observable.Generate
就很容易做到,如下所示:
Func<int, IObservable<int>> mkInts = init =>
Observable.Generate(
init, // start value
_ => true, // continue ?
i => i + 1, // transformation function
i => i); // result selector
using (mkInts(1).Subscribe(Console.WriteLine))
{
Console.ReadLine();
}
这将很高兴在我的屏幕上写下数字直到我按下回车键。但是,我的转换函数执行一些网络 IO,因此类型为 Func
,因此我无法使用该方法。相反,我尝试过这个:
// simulate my transformation function
Func<int, IObservable<int>> mkInt = ts =>
Observable.Return(ts)
.Delay(TimeSpan.FromMilliseconds(10));
// pre-assign my generator function, since the function calls itself recursively
Func<int, IObservable<int>> mkInts = null;
// my generator function
mkInts = init =>
{
var ints = mkInt(init);
// here is where I depend on the previous value.
var nextInts = ints.SelectMany(i => mkInts(i + 1));
return ints.Concat(nextInts);
};
using (mkInts(1).Subscribe(Console.WriteLine))
{
Console.ReadLine();
}
但是在打印大约 5000 个数字后,这将发生堆栈溢出。我该如何解决这个问题?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我想我已经为您提供了一个很好的干净的解决方案。
首先,回到使用
Func
- 它可以使用Func>
轻松转换为Func>
>Observable.FromAsyncPattern。我用它来测试:
现在这是赚钱的地方:
迭代函数变成了异步可观察的。
q 变量将来自主题的值输入到可观察迭代函数中,并选择计算出的可观察值。 Switch 方法使结果变平,并确保对可观察迭代函数的每次调用都得到正确清理。
此外,使用
CompositeDisposable
允许将两个订阅作为一个进行处理。非常整洁!它很容易使用,如下所示:
现在您有了生成器函数的完全参数化版本。不错吧?
I think I've got a nice clean solution for you.
First-up, go back to using a
Func<int, int>
- it can easily be turned into aFunc<int, IObservable<int>>
usingObservable.FromAsyncPattern
.I used this for testing:
Now here's the money maker:
The iterating function is turned into an asynchronous observable.
The
q
variable feeds the values from the subject into the observable iterating function and selects the calculated observable. TheSwitch
method flattens out the result and ensures that each call to the observable iterating function is properly cleaned up.Also, the use of a
CompositeDisposable
allows the two subscriptions to be disposed of as one. Very neat!It's easily used like this:
Now you have a fully parametrized version of your generator function. Nice, huh?
我找到 以下答案正确,但有点太复杂了。
我建议的唯一更改是 mkInts 方法:
I find the following answer correct, but a little too complicated.
The only change I suggest is the mkInts method:
我不完全确定您是否打算将函数的最终结果再次反馈到函数中,或者您是否打算有一个单独的函数来获取下一个输入,所以我两者都做了。这里的技巧是让 IScheduler 完成重复调用的繁重工作。
I was not entirely sure if you meant to feed the eventual result of the function back into the function again or if you meant to have a separate function that would get the next input, so I made both. The trick here is to let the
IScheduler
do the heavy lifting of the repeated calls.我相信代码不是尾递归,因此会导致异常。下面的代码可以正常工作,没有任何此类异常。
或者通过修改您的代码,例如:
I believe the code is not tail recursive and hence causes SO exception. Below is the code which works fine without any such exception.
Or by modifying your code like:
我找到了一个解决方案,虽然它可能不是最漂亮的,但可以达到我想要的效果。如果有人有更好的解决方案,我会将其标记为答案。
I found a solution, which, although it may not be the prettiest, does what I want it to. If anyone has a better solution, I will mark that as an answer.