当前位置: 首页 > 知识库问答 >
问题:

生锈递归类型难度

柳联
2023-03-14

代码是对更复杂代码的简化,以隔离问题:

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 nightly (9c31d76e9 2016-10-03)。

该代码是一个结构,其中包含指向相同结构类型数组的 Vec 的指针。这些受累的数组被递归地称为在编写器中应用一些写入(W trait约束被删除,因为它与问题无关),并且在实际代码中,在某些情况下,ExtWrite成为Writer

在某些地方,性状解析变得时髦,导致类型递归,在考虑W性状解析的单态时,递归似乎相当合乎逻辑。根据递归的深度,MCW将包含无限数量的可能类型,但这实际上与MCW的使用(在原始代码中需要)有关,并且read_end函数的W参数不与结构定义相关联,而是与此函数的无限可能变化相关联。

然而,在这个代码段中,W始终是(),而MCW应该始终是MCW

我在寻求简化时遇到的类似情况:

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,一种用作临时写入器的轻质结构,导致其使用寿命复杂化。这只发生在递归情况下。这似乎真的很边缘,我不知道它是否更像是一个错误或预期的限制。我也试图使用更高等级的特征边界,但在这种情况下,我们真的在结构上工作,我的几次尝试都没有成功。

我可以简单地重新设计< code>TSW(在我的真实例子中,我只有一个可选指针指向一个包含< code>TSW的< code>Vec的结构),并引入一个没有< code>Vec指针的< code>TSW_2,但是作为一个解决方案,这感觉真的很糟糕(至少不令人满意)。

-编辑

是的,谢谢马蒂厄,这是正确的诊断(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>, > ...

事实上,在考虑原始问题时,类型应该完全是...断续器

回顾一下,我记得第一次出现这个问题是为了链接我的W,然后通过使用一个vec来存储它们来解决它(然后我得到了一个具有迭代多层写入的单类型),但随后我需要使用这个vec在以前的vec中写入一些有效负载,在这里我应该使用相同的推理和双数组)。但我做这件事的方式是简单地用一个胖指针在一个可选结构上进行尝试。这并不顺利,因为我做了类似“选项”的事情

所以我希望我最终得到了我的解决方案:使用Vec

共有1个答案

曾德水
2023-03-14

你在这里打乒乓球,看不到尽头。

  • 调用<代码>TSW

递归的每一个新层次都堆积在一个新的类型上,这就是错误消息中的类型如此之大的原因。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();
    }
}

它要简单得多,不会导致试图实例化无限数量的函数,并且可能根本不是您正在寻找的功能:)

 类似资料:
  • 作为考试准备的一部分,我一直在努力解决问题,我想我需要你的帮助。我需要写一个布尔方法,需要整数数组(正和负),并返回true,如果数组可以被拆分为两个相等的组,每个组的数字的量等于另一组。对于示例,对于这个数组: 该方法将返回true,因为-3514=12-913。 对于此阵列: 该方法将返回false,因为即使-3 5 14 -12 = -9 13,等式每边的数字量也不相等。 对于阵列: 该方法

  • 我目前正试图理解两者之间的区别

  • 问题内容: 我的一个朋友在Java API(https://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html)中找到了这个窍门, 并通过阅读以下文章https://docs.oracle.com/javase/tutorial/java/generics/genTypes.html我可以理解上述行在语法上的含义,但是从给出的示例中我无法弄清

  • 我的一个朋友在Java API中发现了这条新闻(https://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html), 通过阅读以下文章https://docs.oracle.com/javase/tutorial/java/generics/genTypes.html我可以理解前面提到的这一行在语法上意味着什么,但从给出的示例中,我无法找出

  • 查看我在某处(这里是游乐场)找到的这个Typescript4.2片段: 我的头不能绕着它。TS如何处理这件事?它怎么不卡在无限递归里?具体地说,对于和的情况,悬停在变量上显示TS将类型解析为和。这是怎么回事?

  • 标准 ML 没有多态递归。在模块语言中添加递归允许我们使用内函子的固定点将多态递归恢复为一种特殊情况。例如: 众所周知,多态递归使得类型推理不可判定。然而,函子定义已经包含部分类型信息,即其参数的签名。这些信息足以使类型推理再次可判定吗?