Rust递归型难度

che*_*eme 2 rust

此代码简化了更复杂的代码以隔离问题:

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() {}
Run Code Online (Sandbox Code Playgroud)

导致以下错误:

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) {
   |   ^
Run Code Online (Sandbox Code Playgroud)

我每晚都在使用Rust(9c31d76e9 2016-10-03).

代码是一个结构,包含指向Vec同一结构类型的数组的指针.这些符号化的数组被递归地调用以在编写器中应用一些写入(W特征约束被删除,因为它与该问题无关),并且在实际代码中ExtWrite变为Writer某些情况.

有一些地方特征解析变得时髦导致类型的递归,当考虑W特征的解析中的单态时,递归似乎相当合乎逻辑.MCW,取决于递归的深度,将包含无数个可能的类型,但这实际上与MCW(原始代码中需要的)的使用有关,并且函数的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() {}
Run Code Online (Sandbox Code Playgroud)

导致:

error: reached the recursion limit while instantiating `rec::<&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&u8>`
  --> <anon>:14:1
   |
14 | fn rec<W>(b: bool, w: &W) {
   | ^
Run Code Online (Sandbox Code Playgroud)

它的行为正确,但我真的没有看到如何在我之前的案例中进行这种改变:

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() {}
Run Code Online (Sandbox Code Playgroud)

看起来MCW,用作临时作家的轻型结构会导致其生命周期复杂化.这只发生在递归的情况下.这似乎真的很边缘,我不知道它是更多的错误或预期的限制.我也试图使用排名更高的特质界限,但在这种情况下,我们真的在结构上工作,我的几次尝试都没有成功.

我可以简单地重新设计TSW(在我的现实情况下,我只可选指针结构包含VecTSW上一个级别),并引入了TSW_2没有指针Vec,但它真的会心疼(在不满意至少)作为解决方案.

- 编辑

是的,感谢Matthieu,这是正确的诊断(MCW误导了我(当测试时我删除了它并且一切运行正常,但它没有做同样的事情):

- TSW<ST>::write_end<()> (&mut sel, w : &mut ())
- MCW<(), TSW<ST>>::write_end_all(&mut self)
- (f from slipt_first mut ) 
        TSW<ST>::write_end<MCW<(),TSW<ST>>
        MCW<MCW<(),TSW<ST>, > ...
Run Code Online (Sandbox Code Playgroud)

事实上,当考虑原始问题时,类型应该完全是...... MCW <MCW <(),TSW,>叠加N次,N是向量的大小.(vec中的元素是Writers扩展,它应该应用于Vec的前一个元素(一种分层编写者)).

回想一下我记得第一个问题是链接我的W然后通过使用vec来存储它们来解决它(然后我得到了单个类型,带有迭代的多层写入),但后来我需要使用这个Vec来编写一些有效载荷. Vec和这里我应该使用相同的推理和双数组).但我这样做的方法是简单地尝试使用胖指针覆盖可选结构.这并不顺利,因为我做了类似"Option <Box <otherstructcontainingvec >>"的事情,但是包含vec的其他结构没有特性,而且在这个示例代码中类似Vec也没有特性.

所以我希望我终于得到了我的解决方案:使用Vec <TSW <E >>(我的结构包含它在实际代码中)作为特征并且有一个真正的胖指针(更优化的解决方案是双维vec(但我的用例是实际上是单一的重叠).

Mat*_* M. 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

它更简单,不会导致尝试实例化无数个函数,并且可能不是您正在寻找的功能:)