此代码简化了更复杂的代码以隔离问题:
use std::marker::PhantomData;
pub trait ExtWrite {
fn write_end<W>(&mut self, &mut W);
}
pub struct ST;
impl ExtWrite for ST {
fn write_end<W>(&mut self, _: &mut W) {}
}
struct MCW<'a, 'b, W: 'a, EW: 'b + ExtWrite>(&'a mut W, &'b mut [EW]);
impl<'a, 'b, W: 'a, EW: 'b + ExtWrite> MCW<'a, 'b, W, EW> {
fn write_end_all(&mut self) {
if let Some((f, last)) = self.1.split_first_mut() {
let mut el = MCW(self.0, last);
f.write_end(&mut el);
// do on current el.write_end();
}
}
}
pub fn rec_test() {
let mut buff = ();
let v: Vec<TSW<ST>> = Vec::new();
let mut el: TSW<ST> = TSW(Box::new(v), PhantomData);
el.write_end(&mut buff);
}
pub struct TSW<E: ExtWrite>(Box<Vec<TSW<E>>>, PhantomData<E>);
impl<E: ExtWrite> ExtWrite for TSW<E> {
fn write_end<W>(&mut self, w: &mut W) {
let mut el = MCW(w, &mut self.0[..]);
el.write_end_all();
}
}
fn main() {}
导致以下错误:
error: reached the recursion limit while instantiating `<TSW<E> as ExtWrite><ST>::write_end::<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<MCW<(), TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>, TSW<ST>>>`
--> <anon>:40:3
|
40 | fn write_end<W>(&mut self, w: &mut W) {
| ^
我每晚都在使用Rust(9c31d76e9 2016-10-03)。
代码是一个结构,包含指向同一结构类型数组的Vec
的指针。这些复杂的数组被递归调用以在编写器中应用一些写入(W
特征约束被删除,因为它与该问题无关),并且在实际代码中ExtWrite
变为Writer
在某些情况下。
有一些地方特性解析变得时髦导致类型的递归,当考虑W
特征的分辨率中的单态时,递归似乎相当合乎逻辑。 MCW
,取决于递归的深度,将包含无数个可能的类型,但这实际上与MCW
的使用(原始代码中需要)以及{{{{{{ 1}} W
函数的参数未链接到结构定义,但具有此函数的无限可能变体。
然而,在此代码段中,read_end
始终为W
,()
应始终为MCW
。
我在寻找简化时遇到的类似情况:
MCW<(),TSW<ST>>
导致:
struct IntSt<'a, W: 'a>(&'a W);
pub fn comp_err() {
let w: u8 = 0;
rec(true, &w);
}
pub struct A(bool);
fn rec<W>(b: bool, w: &W) {
if (b) {
rec(false, &IntSt(w).0);
// rec(false, w)
}
}
fn main() {}
它的行为正确,但我真的没有看到如何在我之前的案例中做出这种改变:
error: reached the recursion limit while instantiating `rec::<&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&u8>`
--> <anon>:14:1
|
14 | fn rec<W>(b: bool, w: &W) {
| ^
它看起来像struct IntSt<'a, W: 'a>(&'a W);
pub fn comp_err() {
let w: u8 = 0;
rec(true, &w);
}
pub struct A(bool);
fn rec<W>(b: bool, w: &W) {
if (b) {
rec(false, IntSt(w).0);
// rec(false, w)
}
}
fn main() {}
,一个用作临时作家的轻型结构,导致其生命周期复杂化。这只发生在递归的情况下。这似乎真的很边缘,我不知道它是更多的错误或预期的限制。我也尝试使用排名较高的特质界限,但在这种情况下,我们真的在结构上工作,我的几次尝试都没有成功。
我可以简单地重新设计MCW
(在我的实际情况中,我只在一个级别上有一个包含TSW
Vec
的结构的可选指针)并引入TSW
没有指向TSW_2
的指针,但它会真的感觉不好(至少不满意)作为解决方案。
- 编辑
是的,感谢Matthieu,这是正确的诊断(MCW误导了我(测试时我将其移除并且一切正常,但它没有做同样的事情):
Vec
事实上,在考虑原始问题时,类型应该完全正确 ...... MCW&lt; MCW&lt;(),TSW,&gt;叠加N次,N是矢量的大小。 (vec中的元素是Writers扩展,它应该适用于Vec的先前元素(分层编写者的类型))。
回顾我记得第一个问题是链接我的W然后通过使用vec来存储它们来解决它(然后我得到了单个Type,带有迭代的多层写法),但是后来我需要用这个Vec写一些以前Vec中的有效负载,这里我应该使用相同的推理和双数组)。但我这样做的方法是简单地尝试使用胖指针覆盖可选结构。这并不顺利,因为我做了类似“Option&lt; Box&lt; otherstructcontainingvec&gt;&gt;”的事情。但是包含vec的其他结构是没有特征的,同样在这个示例代码中,Vec也没有特征。
所以我希望我终于得到了我的解决方案:使用Vec&lt; TSW&lt; E&gt;&gt; (我的结构包含它在实际代码中)作为特征并且有一个真正的胖指针(更优化的解决方案将是双维vec(但我的用例实际上是单个重叠)。
答案 0 :(得分:7)
你有一个乒乓球在这里,看不到尽头。
TSW<E>::write_end<W>(&mut self, w : &mut W)
MCW<W, TSW<E>>::write_end_all(&mut self)
TSW<E>::write_end<MCW<W, TCW<E>>>(&mut self, w: &mut )
每个新级别的递归都会在新类型上堆积,这就是为什么错误消息中的类型如此之大。 rustc编译器,而不是进入无限循环,告诉你,你可能不想实例化无数个函数。
这里的逻辑有问题。那不是一辈子的事。
当开始递归时,你需要一个退出策略的计划:它应该以可预测的方式结束。
在泛型类型的递归的特定情况下,它应该可以预测地结束参数的运行时值。
不知道正确的逻辑应该是什么,我给你一个迭代的解决方案:
fn write_end_all(&mut self) {
for ew in self.1.iter_mut().rev() {
ew.write_end(self.0);
// do on current el.write_end();
}
}
它更简单,不会导致尝试实例化无数个函数,并且可能不是您正在寻找的功能:)