使用自我回调
callback using self
我正在尝试使用一个使用对象的 self 参数的回调。阻止编译的部分是 self.make_sandwhich() 位。我怎样才能做这样的事情并让它真正编译成 Rust? objective 是为了让 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();
}
您发布的设计无法使用。在 ThingUser::get_thing
中需要 &mut self
,这意味着 self
是 &mut dyn ThingUser
类型的借用。闭包|| { self.make_sandwhich() }
也必须借用self
(虽然它只需要一个非mut
的&dyn ThingUser
来调用make_sandwhich
)。 self
的借用必须与闭包一样长。
但是,您想将闭包存储在 Potato
中。这意味着在存储它之后 Potato
也在借用 &ThingUser
,但是 Potato
根本没有定义为借用任何东西(在 potato 的定义中没有生命周期参数)。因此,您将能够传递给 give_callback
的任何闭包都必须 具有 'static
生命周期(这意味着它不会借用任何东西,除了可能存在的东西节目的整个长度)。
这就是您的编译器错误所表达的内容 (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`
编译器阻止你这样做:
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!
大体上你有两个选择。
首先是用生命周期参数定义 Potato
,但这很快就会变得混乱,因为生命周期参数将与马铃薯类型相关联,并且几乎每次使用 Potato
都会变得复杂曾经。
第二个(可能更可取)选项是让您的闭包具有 'static
生命周期。例如,这可以通过将您的人存储在 Arc<Person>
中来完成。然后使用 move
闭包创建一个拥有 Arc<Person>
的闭包,这样 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
来格式化您的代码(最好是在每次保存时)。它将使您更快地编写它并帮助人们阅读它。
我正在尝试使用一个使用对象的 self 参数的回调。阻止编译的部分是 self.make_sandwhich() 位。我怎样才能做这样的事情并让它真正编译成 Rust? objective 是为了让 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();
}
您发布的设计无法使用。在 ThingUser::get_thing
中需要 &mut self
,这意味着 self
是 &mut dyn ThingUser
类型的借用。闭包|| { self.make_sandwhich() }
也必须借用self
(虽然它只需要一个非mut
的&dyn ThingUser
来调用make_sandwhich
)。 self
的借用必须与闭包一样长。
但是,您想将闭包存储在 Potato
中。这意味着在存储它之后 Potato
也在借用 &ThingUser
,但是 Potato
根本没有定义为借用任何东西(在 potato 的定义中没有生命周期参数)。因此,您将能够传递给 give_callback
的任何闭包都必须 具有 'static
生命周期(这意味着它不会借用任何东西,除了可能存在的东西节目的整个长度)。
这就是您的编译器错误所表达的内容 (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`
编译器阻止你这样做:
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!
大体上你有两个选择。
首先是用生命周期参数定义 Potato
,但这很快就会变得混乱,因为生命周期参数将与马铃薯类型相关联,并且几乎每次使用 Potato
都会变得复杂曾经。
第二个(可能更可取)选项是让您的闭包具有 'static
生命周期。例如,这可以通过将您的人存储在 Arc<Person>
中来完成。然后使用 move
闭包创建一个拥有 Arc<Person>
的闭包,这样 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
来格式化您的代码(最好是在每次保存时)。它将使您更快地编写它并帮助人们阅读它。