Rust 在线程之间发送装箱特征

Rust 在线程之间发送装箱特征,rust,Rust,我一直在玩rust,我正在做一个非常愚蠢的程序,它结合了特性、结构、一些愚蠢的并发性和泛型。对我来说,一切都是可以理解的,直到我在线程之间发送特征时遇到了一些问题 首先,a意识到我需要一个装箱动物的向量来存储符合动物特征的不同元素,好吧,我明白了,因为特征是一些其他特殊结构的抽象,这些结构可能在“大小”等方面有所不同,所以我们必须将它们存储在堆中。 但对我来说,第一个奇怪的地方是,因为我必须使用一个框来存储特征,所以我还必须为装箱的特征实现我的特征(参见代码注释中的(*1)) 一旦我这样做了,程

我一直在玩rust,我正在做一个非常愚蠢的程序,它结合了特性、结构、一些愚蠢的并发性和泛型。对我来说,一切都是可以理解的,直到我在线程之间发送特征时遇到了一些问题

首先,a意识到我需要一个装箱动物的向量来存储符合动物特征的不同元素,好吧,我明白了,因为特征是一些其他特殊结构的抽象,这些结构可能在“大小”等方面有所不同,所以我们必须将它们存储在堆中。 但对我来说,第一个奇怪的地方是,因为我必须使用一个框来存储特征,所以我还必须为装箱的特征实现我的特征(参见代码注释中的(*1))

一旦我这样做了,程序对于编译器来说是正确的,但是我在运行时遇到了一些我不理解的问题。 我得到的错误是:

thread '<unknown>' has overflowed its stack
fatal runtime error: stack overflow
[1]    4175 abort (core dumped)  cargo run
线程“”已溢出其堆栈
致命的运行时错误:堆栈溢出
[1] 4175中止(堆芯卸载)货物运行
代码是:

use std::thread;
use std::sync::mpsc::{Sender};
use std::sync::mpsc;
use std::time;

trait Animal {
    fn poop(&self) -> Poop;
}

#[derive(Debug)]
enum Weight {
    VeryLight,
    Light,
    Medium,
    Heavy,
    SuperHeavy,
}

#[derive(Debug)]
struct Poop {
    shape: String,
    weight: Weight,
}

struct Wombat;

impl Animal for Wombat {
    fn poop(&self) -> Poop {
        Poop {
            shape: "cubic".to_string(),
            weight: Weight::Light,
        }
    }
}

struct Cat;

impl Animal for Cat {
    fn poop(&self) -> Poop {
        Poop {
            shape: "cylindrical".to_string(),
            weight: Weight::VeryLight,
        }
    }
}

// (*1) This seemed weird for me and I'm not sure the 
// impl es correct
impl Animal for Box<dyn Animal + Send> {
    fn poop(&self) -> Poop {
        let t: &dyn Animal = self;
        // self.poop()
        t.poop()

    }
}

fn feed_animal<T> (a: T, tx: Sender<String>)
    where T: Animal + Send + 'static {
    
    thread::spawn(move || {
        thread::sleep(time::Duration::from_secs(2));
        tx.send(format!("{:?}", a.poop()))
    });
}

fn main() {
    let mut animals: Vec<Box<dyn Animal + Send>> = Vec::new();
    animals.push(Box::new(Wombat));
    animals.push(Box::new(Cat));
    
    let (tx, rx) = mpsc::channel();

    for a in animals {
        let txi = tx.clone();
        feed_animal(a, txi);
    }

    drop(tx);

    for r in rx {
        println!("The animal just pooped: {:?}", r);
    }
}
使用std::thread;
使用std::sync::mpsc::{Sender};
使用std::sync::mpsc;
使用std::时间;
特征动物{
fn-poop(&self)->poop;
}
#[导出(调试)]
枚举权重{
非常轻,
轻,,
中等,
沉重的,
超重,
}
#[导出(调试)]
结构粪便{
形状:弦,
重量:重量,,
}
结构袋熊;
袋熊用动物{
fn起下钻(和自)->起下钻{
大便{
形状:“立方体”。到字符串(),
重量:重量:轻,
}
}
}
结构猫;
猫科动物{
fn起下钻(和自)->起下钻{
大便{
形状:“圆柱形”。至_字符串(),
重量:重量:非常轻,
}
}
}
//(*1)这对我来说似乎很奇怪,我不确定
//暗示正确
为盒子装动物{
fn起下钻(和自)->起下钻{
让t:&dyn动物=自我;
//self.poop()
t、 大便
}
}
fn饲料动物(a:T,tx:发送者)
其中T:Animal+Send+'静态{
线程::生成(移动| |{
线程::睡眠(时间::持续时间::from_secs(2));
tx.send(格式!(“{:?}”,a.poop())
});
}
fn main(){
让mut动物:Vec=Vec::new();
动物。推(盒子:新的(袋熊));
动物。推(盒::新(猫));
let(tx,rx)=mpsc::channel();
对于动物来说,这是一个巨大的挑战{
设txi=tx.clone();
饲养动物(a,txi);
}
下降(tx);
对于rx中的r{
println!(“刚拉屎的动物:{:?}”,r);
}
}
老实说,我对这个错误消息有点不知所措。通常,当我在一些其他编程语言中看到这种错误时,是由于一个无限循环导致堆栈溢出,但在这种情况下,我猜在我将装箱特征“发送”给子线程的方式中肯定存在一些错误,这使得rust在运行时无法很好地处理子线程堆栈内存。。我不确定

任何正确方向的暗示都将受到欢迎。
谢谢。

让我们关注以下代码:

impl-Animal for-Box{
fn起下钻(和自)->起下钻{
让t:&dyn动物=自我;
//self.poop()
t、 大便
}
}
在这里,我们得到
&Box
类型的
self
,将其投射到
&dyn Animal
,并使其
大便

我相信你被间接层次弄糊涂了,尤其是另外一个
&
的存在。通过将
Box
投射到
dyn Animal
,您可以获得
Box
的动态版本。稍后,在该动态化版本上调用
poop
,这会使函数无意中递归

正确的代码是

让t:&dyn动物=&**self;

顺便说一下,有一些工具可以在出现问题时获取堆栈跟踪。一个这样的解决方案,一个多用途的解决方案,是运行
valgrind target/debug/your binary

让我们重点关注以下代码:

impl-Animal for-Box{
fn起下钻(和自)->起下钻{
让t:&dyn动物=自我;
//self.poop()
t、 大便
}
}
在这里,我们得到
&Box
类型的
self
,将其投射到
&dyn Animal
,并使其
大便

我相信你被间接层次弄糊涂了,尤其是另外一个
&
的存在。通过将
Box
投射到
dyn Animal
,您可以获得
Box
的动态版本。稍后,在该动态化版本上调用
poop
,这会使函数无意中递归

正确的代码是

让t:&dyn动物=&**self;

顺便说一下,有一些工具可以在出现问题时获取堆栈跟踪。一个这样的解决方案,一个多用途的解决方案,是运行
valgrind target/debug/your binary

我对您的代码做了一些更改。你可以用这个来检查

我认为你在函数签名中犯了一个错误

fn feed_animal<T> (a: T, tx: Sender<String>)
    where T: Animal + Send + 'static {
}

我对你的代码做了一点修改。你可以用这个来检查

我认为你在函数签名中犯了一个错误

fn feed_animal<T> (a: T, tx: Sender<String>)
    where T: Animal + Send + 'static {
}

那么让我们看看我是否理解正确。&**引用:*)获取框的值(它是指向堆的指针)*)获取指向堆的指针的值(它指向动物)&)获取存储在堆中的动物的引用是否正确?让我们看看我当时是否理解正确。&**引用:*)获取框的值(指向堆的指针)*)获取指向堆的指针的值(指向动物)&)获取指向堆中存储的动物的引用是否正确?好的,我明白你的意思,没有考虑这个选项。但是,这是“惯用的”锈迹吗?哪一个是最好的选择?因为,例如,我在定义“喂养动物”函数时的推理是。。“我想接收符合动物特征的T型输入”;这是我对代码的说明。但是,r会吗