So I have this trait and a struct that implements it:
trait Trait {
fn foo(&self) -> u64;
}
/// No Copy trait supported because it's expensive
struct Expensive {
id: u64,
}
impl Trait for Expensive {
fn foo(&self) -> u64 {
self.id
}
}
I have another structure that I wish to be global, that contains the trait:
struct Cheap {
pub item: Box<dyn Trait>,
}
thread_local! {
static CHEAP: Cheap = Cheap {
item: Box::new(Expensive {
id: 4
})
}
}
fn trait_item() -> Box<dyn Trait> {
CHEAP.with(|c| c.item)
}
This fails because
error[E0507]: cannot move out of `c.item` which is behind a shared reference
--> src/main.rs:35:20
|
35 | CHEAP.with(|c| c.item)
| ^^^^^^ move occurs because `c.item` has type `std::boxed::Box<dyn Trait>`, which does not implement the `Copy` trait
It's not really feasible to always do the processing within the .with(...) part, because some functions that take in the Trait don't care where it comes from. So I try to return a reference to it instead:
fn trait_item<'a>() -> &'a Box<dyn Trait> {
CHEAP.with(|c| &c.item)
}
This also fails because I cannot send a reference outside of the with:
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:33:20
|
33 | CHEAP.with(|c| &c.item)
| ^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 33:16...
--> src/main.rs:33:16
|
33 | CHEAP.with(|c| &c.item)
| ^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:33:20
|
33 | CHEAP.with(|c| &c.item)
| ^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 32:15...
--> src/main.rs:32:15
|
32 | fn trait_item<'a>() -> &'a Box<dyn Trait> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:33:5
|
33 | CHEAP.with(|c| &c.item)
| ^^^^^^^^^^^^^^^^^^^^^^^
So instead I wrap the whole thing in an Rc like so:
struct Cheap {
pub item: Rc<Box<dyn Trait>>,
}
thread_local! {
static CHEAP: Cheap = Cheap {
item: Rc::new(Box::new(Expensive {
id: 4
}))
}
}
fn trait_item() -> Rc<Box<dyn Trait>> {
CHEAP.with(|c| c.item.clone())
}
But now clippy complains:
warning: usage of `Rc<Box<T>>`
--> src/main.rs:41:15
|
41 | pub item: Rc<Box<dyn Trait>>,
| ^^^^^^^^^^^^^^^^^^ help: try: `Box<dyn Trait>`
|
= note: `#[warn(clippy::redundant_allocation)]` on by default
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
warning: usage of `Rc<Box<T>>`
--> src/main.rs:53:20
|
53 | fn trait_item() -> Rc<Box<dyn Trait>> {
| ^^^^^^^^^^^^^^^^^^ help: try: `Box<dyn Trait>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
warning: 2 warnings emitted
Am I missing something, or is it not actually possible to do what clippy recommends here?
Rust playground | Relevant Clippy page
You can wrap a trait object in a Rc as well, since Rc is also a pointer.
Therefore if you have Rc<Box<T>>, you have two allocations: One for the T and one for the Box (another pointer, that now is on the heap). Instead, use Rc<dyn MyTrait> to only have one allocation.
Related
Code:
trait MyTrait {
fn update(&self, _prev: &Self) { unimplemented!() }
}
trait MyOtherTrait<'a> {}
pub struct MyTraitDynWrapper<'a> {
// When v1 commented out, code works
v1: &'a dyn MyOtherTrait<'a>,
v2: &'a (),
}
impl<'a> MyTrait for MyTraitDynWrapper<'a> {}
struct Container;
impl Container {
// GENERATED BY PROC MACRO: CANNOT CHANGE
fn with_ref<'outer_borrow, ReturnType>(
&'outer_borrow self,
user: impl for<'this> FnOnce(&'outer_borrow MyTraitDynWrapper<'this>) -> ReturnType,
) -> ReturnType {
unimplemented!()
}
}
fn main() {
let a = Container;
let b = Container;
a.with_ref(|a| {
b.with_ref(|b| {
MyTrait::update(a, b)
})
});
}
When compiling as-is, I get a lifetime errors complaining, in main, that the lifetime of b in the closure may not outlive the lifetime of a, even though it should be fine since the call doesn't borrow anything for longer than the call.
If I comment out the v1 field of MyTraitDynWrapper, the code compiles fine.
Container::with_ref is a simplification of a method that the ouroboros crate generates (its similar to rental), and I cannot change it.
What's happening with this code and how can I fix the error while still being able to use the trait object?
Error:
error[E0308]: mismatched types
--> src/lib.rs:33:23
|
33 | MyTrait::update(a, b)
| ^ lifetime mismatch
|
= note: expected reference `&MyTraitDynWrapper<'_>`
found reference `&MyTraitDynWrapper<'_>`
note: the anonymous lifetime #2 defined on the body at 32:14...
--> src/lib.rs:32:14
|
32 | b.with_ref(|b| {
| ____________________^
33 | | MyTrait::update(a, b)
34 | | })
| |_________^
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 31:13
--> src/lib.rs:31:13
|
31 | a.with_ref(|a| {
| ________________^
32 | | b.with_ref(|b| {
33 | | MyTrait::update(a, b)
34 | | })
35 | | });
| |_____^
error[E0308]: mismatched types
--> src/lib.rs:33:23
|
33 | MyTrait::update(a, b)
| ^ lifetime mismatch
|
= note: expected reference `&MyTraitDynWrapper<'_>`
found reference `&MyTraitDynWrapper<'_>`
note: the anonymous lifetime #2 defined on the body at 31:13...
--> src/lib.rs:31:13
|
31 | a.with_ref(|a| {
| ________________^
32 | | b.with_ref(|b| {
33 | | MyTrait::update(a, b)
34 | | })
35 | | });
| |_____^
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 32:14
--> src/lib.rs:32:14
|
32 | b.with_ref(|b| {
| ____________________^
33 | | MyTrait::update(a, b)
34 | | })
| |_________^
error: aborting due to 2 previous errors
&'a dyn Trait<'a> has many the same problems &'a mut Struct<'a> does. Because traits (and therefore trait objects) are invariant over their lifetime parameters, once you put 'a in a trait, the compiler can no longer vary it to try to satisfy lifetime constraints.
You cannot tell the compiler that a trait is covariant, but if you can't simply remove the lifetime parameter from MyOtherTrait entirely, you might use a higher-ranked trait bound (HRTB) to say that MyOtherTrait is not parameterized with 'a within MyTraitDynWrapper<'a>:
pub struct MyTraitDynWrapper<'a> {
v1: &'a dyn for<'b> MyOtherTrait<'b>,
v2: &'a (),
}
If not for the constraint that you can't change with_ref, you could make 'a and 'b both parameters of MyTraitDynWrapper:
pub struct MyTraitDynWrapper<'a, 'b> {
v1: &'a dyn MyOtherTrait<'b>,
v2: &'a (),
}
// ...
impl Container {
// GENERATED BY PROC MACRO: CANNOT CHANGE
fn with_ref<'outer_borrow, 'that, ReturnType>(
&'outer_borrow self,
user: impl for<'this> FnOnce(&'outer_borrow MyTraitDynWrapper<'this, 'that>) -> ReturnType,
) -> ReturnType {
unimplemented!()
}
}
However, if none of these options work for you, it's not clear what else you could do that would be sound. Bear in mind that traits can be implemented by all kinds of types, so the compiler is protecting you not just from your own code but from any code that might be written.
See also
How do I implement the Chain of Responsibility pattern using a chain of trait objects?
I'm a newbie of concurrency. The context is I spawn a thread that using a method with a lifetime in a struct method. Then I got an error cannot infer an appropriate lifetime due to conflicting requirements
Here is a simplified example of my code.
use std::thread;
use std::time::Duration;
struct Printer{
prefix: &'static str,
}
impl Printer {
pub fn print(&self, text: String) {
println!("{}: {}", self.prefix, text);
}
pub fn new(prefix: &'static str) -> Self {
Printer {
prefix: prefix
}
}
}
struct Foo<'a> {
printer: &'a Printer
}
impl<'a> Foo<'a> {
fn pop(&self) {
thread::spawn(|| {
self.printer.print(String::from("pop"));
});
}
pub fn new(printer: &'a Printer) -> Self {
Foo {
printer: printer
}
}
}
fn main() {
let printer = Printer::new("freaking");
printer.print(String::from("hell"));
let foo = Foo::new(&printer);
foo.pop();
}
Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:28:23
|
28 | thread::spawn(|| {
| _______________________^
29 | | self.printer.print(String::from("pop"));
30 | | });
| |_________^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 26:6...
--> src/main.rs:26:6
|
26 | impl<'a> Foo<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:28:23
|
28 | thread::spawn(|| {
| _______________________^
29 | | self.printer.print(String::from("pop"));
30 | | });
| |_________^
= note: expected `&&Foo<'_>`
found `&&Foo<'a>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure#src/main.rs:28:23: 30:10 self:&&Foo<'_>]` will meet its required lifetime bounds
--> src/main.rs:28:9
|
28 | thread::spawn(|| {
| ^^^^^^^^^^^^^
error: aborting due to previous error
How could I avoid this error? Is it an anti-pattern for concurrency?
The following didn't compile:
use std::any::Any;
pub trait CloneBox: Any {
fn clone_box(&self) -> Box<dyn CloneBox>;
}
impl<T> CloneBox for T
where
T: Any + Clone,
{
fn clone_box(&self) -> Box<dyn CloneBox> {
Box::new(self.clone())
}
}
struct Foo(Box<dyn CloneBox>);
impl Clone for Foo {
fn clone(&self) -> Self {
let Foo(b) = self;
Foo(b.clone_box())
}
}
Error message:
error[E0495]: cannot infer an appropriate lifetime for pattern due to conflicting requirements
--> src/lib.rs:20:17
|
20 | let Foo(b) = self;
| ^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 19:5...
--> src/lib.rs:19:5
|
19 | / fn clone(&self) -> Self {
20 | | let Foo(b) = self;
21 | | Foo(b.clone_box())
22 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:20:17
|
20 | let Foo(b) = self;
| ^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `&std::boxed::Box<dyn CloneBox>` will meet its required lifetime bounds
--> src/lib.rs:21:15
|
21 | Foo(b.clone_box())
|
However if change the code in clone() from Foo(b.clone_box()) to Foo(self.0.clone_box()), it compiles without problem. In theory, field access should be the same as pattern matching, but why does pattern matching have lifetime issues?
In my real code, the data is in an enum, not a struct, so pattern matching is the only option.
TL;DR: Dereference the value before calling the method:
Foo((*b).clone_box())
With let Foo(b) = self, the type of b is &Box<(dyn CloneBox + 'static)>. The method call is effectively
Foo(<&Box<dyn CloneBox + 'static> as CloneBox>::clone_box(&b))
This value cannot be made into the trait object Box<dyn CloneBox + 'static> because of the local reference. Amusingly, I believe this would be recursively using the blanket implementation if the compiler allowed it.
With self.0.clone_box(), the method call is effectively:
Foo(<dyn CloneBox as CloneBox>::clone_box(&**b)
We could write this as Foo((&**b).clone_box()) to be explicit, but since there's no intermediate implementations, Foo((*b).clone_box()) is sufficient.
See also:
What are Rust's exact auto-dereferencing rules?
trait BT {
fn get_a(&self) -> &A;
}
#[derive(Debug)]
struct A {
v: i32,
}
impl A {
fn nb(&self) -> Box<BT> {
Box::new(B { a: self })
}
}
#[derive(Debug)]
struct B<'a> {
a: &'a A,
}
impl<'a> BT for B<'a> {
fn get_a(&self) -> &A {
return self.a;
}
}
fn main() {
println!("{:?}", A { v: 32 }.nb().get_a());
}
A has a method to generate a B instance with a reference of A, and B might have many methods access B.a (A's reference in B). If let A.nb() return B instead of BT, the code would work well.
I'm new to Rust. This problem has troubled me all day. What should I do to make this code work? Thanks!
The whole error report:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src\socket\msg\message.rs:53:26
|
53 | Box::new(B{a: self})
| ^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 52:13...
--> src\socket\msg\message.rs:52:13
|
52 | / fn nb(&self) -> Box<BT> {
53 | | Box::new(B{a: self})
54 | | }
| |_____________^
note: ...so that reference does not outlive borrowed content
--> src\socket\msg\message.rs:53:31
|
53 | Box::new(B{a: self})
| ^^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<socket::msg::message::test::test::BT + 'static>
found std::boxed::Box<socket::msg::message::test::test::BT>
The default lifetime of a trait object is 'static. You need to add an explicit lifetime bound to the trait object returned by nb() function:
impl A {
fn nb<'s>(&'s self) -> Box<BT+'s> {
Box::new(B{a: self})
}
}
Inference of Trait Object Lifetimes
I'm trying to implement a memory pool based on TypedArena. Here's a simplified version of my original code:
#![feature(rustc_private)]
extern crate arena;
use arena::TypedArena;
pub struct MemoryPool {
arena: TypedArena<Vec<u8>>,
bytes_allocated: usize,
}
impl MemoryPool {
pub fn consume(&mut self, buf: Vec<u8>) -> &[u8] {
self.bytes_allocated += buf.capacity();
self.arena.alloc(buf)
}
}
pub struct ByteArray<'a> {
data: &'a [u8],
}
impl<'a> ByteArray<'a> {
pub fn set_data(&mut self, data: &'a [u8]) {
self.data = data;
}
}
pub struct S<'a> {
pool: &'a mut MemoryPool,
}
impl<'a> S<'a> {
pub fn write(&mut self, buffer: &mut ByteArray<'a>) {
let v = vec!();
let data = self.pool.consume(v);
buffer.set_data(data);
}
}
However, the compiler complains about the line: let data = self.pool.consume(v);:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> <anon>:34:26
|
34 | let data = self.pool.consume(v);
| ^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 32:54...
--> <anon>:32:55
|
32 | pub fn write(&mut self, buffer: &mut ByteArray<'a>) {
| _______________________________________________________^ starting here...
33 | | let v = vec!();
34 | | let data = self.pool.consume(v);
35 | | buffer.set_data(data);
36 | | }
| |___^ ...ending here
note: ...so that reference does not outlive borrowed content
--> <anon>:34:16
|
34 | let data = self.pool.consume(v);
| ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the body at 32:54...
--> <anon>:32:55
|
32 | pub fn write(&mut self, buffer: &mut ByteArray<'a>) {
| _______________________________________________________^ starting here...
33 | | let v = vec!();
34 | | let data = self.pool.consume(v);
35 | | buffer.set_data(data);
36 | | }
| |___^ ...ending here
note: ...so that types are compatible (expected &mut ByteArray<'_>, found &mut ByteArray<'a>)
--> <anon>:35:12
|
35 | buffer.set_data(data);
| ^^^^^^^^
My question is:
Why data does not have lifetime 'a? I'm thinking that since pool has lifetime a and consume returns the same lifetime as self, it should have lifetime 'a.
What's the best way to make this code work as intended? Basically I want to allocate new bytes and adjust their lifetime to be the same as the memory pool. I know I can use TypedArena directly since alloc does not take a mut reference. However I really want to track other information such as bytes_allocated.
Let's tackle this step by step:
cannot infer an appropriate lifetime for autoref
"autoref" describes the process of building the right reference for the self argument of a method. The compiler is unable to find a reference with the right lifetime to call consume(). Why is it unable?
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 32:54...
--> <anon>:32:55
|
32 | pub fn write(&mut self, buffer: &mut ByteArray<'a>) {
| _______________________________________________________^ starting here...
33 | | let v = vec!();
34 | | let data = self.pool.consume(v);
35 | | buffer.set_data(data);
36 | | }
| |___^ ...ending here
note: ...so that reference does not outlive borrowed content
--> <anon>:34:16
|
34 | let data = self.pool.consume(v);
| ^^^^^^^^^
The "anonymous lifetime #1" refers to the lifetime of &mut self. This note is just saying: we can't pass a reference with a lifetime greater than the lifetime of self into consume(): then consume() would think that its self argument lives longer than it actually does.
note: but, the lifetime must be valid for the lifetime 'a
This is the rule you already expected to be applied. But where is the problem now? Well: the lifetime of &mut self (anonymous lifetime #1) could life shorter than 'a! That's all! And we can fix it quite easily:
impl<'a> S<'a> {
pub fn write<'b: 'a>(&'b mut self, buffer: &mut ByteArray<'a>) {
// ^^^^^^^^ ^^
...
}
}
Here we just name the previously anonymous lifetime #1 to be able to bound it, saying that it has to outlive 'a (live longer than 'a).