使用自我回调

发布于 2025-01-25 01:48:49 字数 1469 浏览 1 评论 0原文

我正在尝试使用使用对象的自我参数的回调。阻止此编译的部分是self.make_sandwhich()位。我该如何做这样的事情并实际上将其编译为Rust?目的是使Thinguser能够为事物指定功能。在这种情况下,当您垃圾土豆时,用户会制作一个沙子。

pub trait Thing {
  fn stuff(&self);
  fn junk(&mut self);
}

pub struct Potato {
    thing: Box<dyn FnMut()+Send>,
}

impl Potato {
  fn new() -> Self {
    Self{
        thing: Box::new(||{println!("Original callback");}),
    }
  }
  
  fn give_callback(&mut self, thing: Box<dyn FnMut()+Send>) {
      self.thing = thing;
  }
}

impl Thing for Potato {
  fn stuff(&self) {
  }
  fn junk(&mut self) {
    (self.thing)();
  }
}

fn make_thing() -> Box<dyn Thing> {
    Box::new(Potato::new())
}

pub trait ThingUser {
    fn get_thing(&mut self) -> Option<Box<dyn Thing>>;
}

pub struct Person {
    
}

impl Person {
    fn make_sandwhich(&self) {
        println!("I made a sandwhich");
    }
}

impl ThingUser for Person {
    fn get_thing(&mut self) -> Option<Box<dyn Thing>> {
        let mut p = Potato::new();
        p.give_callback(Box::new(||{self.make_sandwhich()}));
        Some(Box::new(p))
    }
}

fn main() {
    println!("Hello, world!");
  let mut p  = Potato::new();
  p.stuff();
  
  p.give_callback(Box::new(||{println!("Callback");}));
  (p.thing)();
  p.junk();
  
  let mut q = make_thing();
  q.junk();
  
  let mut tu = Person{};
  let used_thing = tu.get_thing();
  used_thing.unwrap().junk();
}

I am trying to use a callback that uses the self parameter of an object. The part that prevents this from compiling is the self.make_sandwhich() bit. How can I do something like this and have it actually compile in rust? The objective is to make ThingUser able to specify functionality for a Thing. In this case, when you junk the potato, the user makes a sandwhich.

pub trait Thing {
  fn stuff(&self);
  fn junk(&mut self);
}

pub struct Potato {
    thing: Box<dyn FnMut()+Send>,
}

impl Potato {
  fn new() -> Self {
    Self{
        thing: Box::new(||{println!("Original callback");}),
    }
  }
  
  fn give_callback(&mut self, thing: Box<dyn FnMut()+Send>) {
      self.thing = thing;
  }
}

impl Thing for Potato {
  fn stuff(&self) {
  }
  fn junk(&mut self) {
    (self.thing)();
  }
}

fn make_thing() -> Box<dyn Thing> {
    Box::new(Potato::new())
}

pub trait ThingUser {
    fn get_thing(&mut self) -> Option<Box<dyn Thing>>;
}

pub struct Person {
    
}

impl Person {
    fn make_sandwhich(&self) {
        println!("I made a sandwhich");
    }
}

impl ThingUser for Person {
    fn get_thing(&mut self) -> Option<Box<dyn Thing>> {
        let mut p = Potato::new();
        p.give_callback(Box::new(||{self.make_sandwhich()}));
        Some(Box::new(p))
    }
}

fn main() {
    println!("Hello, world!");
  let mut p  = Potato::new();
  p.stuff();
  
  p.give_callback(Box::new(||{println!("Callback");}));
  (p.thing)();
  p.junk();
  
  let mut q = make_thing();
  q.junk();
  
  let mut tu = Person{};
  let used_thing = tu.get_thing();
  used_thing.unwrap().junk();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

拍不死你 2025-02-01 01:48:49

您发布的设计无法正常工作。在Thinguser :: get_thing中采用&amp; mut self,这意味着self是类型&amp; mut dyn thinguser的借用。闭合|| {self.make_sandwhich()}还必须借用self(尽管它只需要非 - mut &amp; dyn thinguser to调用make_sand)。 self的借用只要封闭生活就必须生存。

但是,您想将封闭存储在马铃薯中。这意味着在存储马铃薯也是借用的&amp; thiteuser,但是马铃薯根本没有定义任何东西(马铃薯的定义中没有终身参数)。因此,您将能够将任何关闭传递给give_callback 必须具有'static lifeTime(这意味着它不借任何东西,除了可能是整个程序长度的生活)。

这就是您的编译器错误所表达的内容(游乐场

error: lifetime may not live long enough
  --> src/main.rs:51:25
   |
49 |     fn get_thing(&mut self) -> Option<Box<dyn Thing>> {
   |                  - let's call the lifetime of this reference `'1`
50 |         let mut p = Potato::new();
51 |         p.give_callback(Box::new(||{self.make_sandwhich()}));
   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`

编译器正在阻止您这样做:

let person = Person {};
let mut potato = Potato::new();
p.give_callback(Box::new(|| { person.make_sandwhich() } ));
drop(person);
potato.junk(); // ! This would be trying to call `person.make_sandwhich()`, but `person` has been dropped! This is a horrible memory safety error!

从广义上讲,您有两个选择。

首先是用终身参数定义马铃薯,但这会随着终生参数与马铃薯类型绑定而迅速变得凌乱,并且几乎可以使每种用途的用途复杂化potagy>马铃薯曾经。

第二个(可能是最好的)选项是使您的关闭具有'静态寿命。例如,可以通过将您的人存储在arc&lt; person&gt;中来完成。然后,您使用移动封闭来创建一个拥有arc&lt; person&gt;的关闭,以便person才能删除直到删除关闭之前。例如

let person = Arc::new(Person {});
let mut potato = Potato::new();
let person_clone = person.clone();  // Not strictly necessary for this simple example, but I'm assuming you might want access to `person` after creating the callback in which case this is necessary
p.give_callback(Box::new(move || { person_clone.make_sandwhich() } ));
drop(person);
potato.junk(); // This is now fine! The first `Arc<Person>` was dropped, but the closure is still holding one so the internal `Person` object has not been dropped. Hooray!

P.S.我强烈建议您使用Rustfmt格式化您的代码(理想情况下,每个保存)。它会让您更快地编写它,并将帮助人们阅读它。

The design you posted cannot work. In ThingUser::get_thing it takes &mut self, which means that self is a borrow of type &mut dyn ThingUser. The closure || { self.make_sandwhich() } must also borrow self (although it only needs a non-mut &dyn ThingUser to call make_sandwhich). That borrow of self must live as long as the closure lives.

However, you want to store the closure inside a Potato. This would mean that after storing it the Potato is also borrowing &ThingUser, but Potato is not defined to borrow anything at all (there are no lifetime parameters in the definition of potato). Therefore any closure you will ever be able to pass to give_callback must have a 'static lifetime (meaning that it doesn't borrow anything, except possibly things that live for the entire length of the program).

This is what's being expressed by your compiler error (playground)

error: lifetime may not live long enough
  --> src/main.rs:51:25
   |
49 |     fn get_thing(&mut self) -> Option<Box<dyn Thing>> {
   |                  - let's call the lifetime of this reference `'1`
50 |         let mut p = Potato::new();
51 |         p.give_callback(Box::new(||{self.make_sandwhich()}));
   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`

The compiler is stopping you from doing this:

let person = Person {};
let mut potato = Potato::new();
p.give_callback(Box::new(|| { person.make_sandwhich() } ));
drop(person);
potato.junk(); // ! This would be trying to call `person.make_sandwhich()`, but `person` has been dropped! This is a horrible memory safety error!

Broadly you have two options.

First would be to define Potato with a lifetime parameter, but this will get messy quickly as the lifetime parameter will by tied to the potato type and will complicate pretty much every use of Potato ever.

The second (probably preferable) option is to make your closure have a 'static lifetime. This could be done by storing your person in an Arc<Person>, for example. Then you use a move closure to create a closure which owns an Arc<Person>, so that Person cannot be dropped until the closure is dropped. For example

let person = Arc::new(Person {});
let mut potato = Potato::new();
let person_clone = person.clone();  // Not strictly necessary for this simple example, but I'm assuming you might want access to `person` after creating the callback in which case this is necessary
p.give_callback(Box::new(move || { person_clone.make_sandwhich() } ));
drop(person);
potato.junk(); // This is now fine! The first `Arc<Person>` was dropped, but the closure is still holding one so the internal `Person` object has not been dropped. Hooray!

P.S. I highly recommend you use rustfmt to format your code (ideally on every save). It will make you faster writing it and will help people read it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文