The following code allows me to downcast from Arc<MyTrait> to Arc<MyStruct>:
trait MyTrait {
fn as_any(self: Arc<Self>) -> Arc<dyn std::any::Any + Send + Sync>;
};
struct MyStruct {};
MyStruct impl MyTrait {
fn as_any(self: std::sync::Arc<Self>) -> std::sync::Arc<dyn std::any::Any + Send + Sync> {
self
}
};
Now I am in the need to downcast from Arc<tokio::sync::RwLock<MyTrait>> to Arc<tokio::sync::RwLock<MyStruct> while keeping the original object alive as it is stored in the list to which other parts of the program have access to?
Adding
fn as_any_rw(self: Arc<tokio::sync::RwLock<Self>>) -> Arc<tokio::sync::RwLock<dyn std::any::Any + Send + Sync>>;
to the trait makes the compiler scream with
invalid `self` parameter type: std::sync::Arc<tokio::sync::RwLock<Self>>
type of `self` must be `Self` or a type that dereferences to it
consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)rustcE0307
I know that using enums is an alternative approach to solve my problem but I have to work with the existing structure.
Related
When I don't include the + 'static in this code, rustc complains. Why?
// adapted from rust-analyzer https://github.com/rust-analyzer/rust-analyzer
trait Upcast<T: ?Sized> {
fn upcast(&self) -> &T;
}
trait DefDatabase {}
trait HirDatabase: Upcast<dyn DefDatabase> {}
struct RootDatabase{}
impl Upcast<dyn DefDatabase> for RootDatabase {
fn upcast(&self) -> &(dyn DefDatabase + 'static) {
&*self
}
}
`impl` item signature doesn't match `trait` item signature
expected `fn(&RootDatabase) -> &(dyn DefDatabase + 'static)`
found `fn(&RootDatabase) -> &dyn DefDatabase`
the lifetime requirements from the `impl` do not correspond to the
requirements in the `trait`
verify the lifetime relationships in the `trait` and `impl` between the
`self` argument, the other inputs and its output
Why is 'static lifetime required?
It seems like the dyn is essential to the example. rustc does not complain about this impl, which doesn't mention 'static:
impl Upcast<RootDatabase> for RootDatabase {
fn upcast(&self) -> &Self {
self
}
}
You need to explicitly state what the lifetime of the Trait Object &'dyn DefDatabase is so that the borrow checker knows what the lifetime of any references held by the struct behind the pointer are. 'static is the default if you do not define it, or it cannot otherwise be determined from the context. See default trait object lifetimes in the rust language reference for more information.
Adding a lifetime to your Upcast trait definition allows you to drop 'static.
trait Upcast<'a, T: ?Sized + 'a> {
fn upcast(&self) -> &T; // 'a is not necessary here because the generic `T` may or may not be a trait object
}
trait DefDatabase {}
struct RootDatabase{}
impl DefDatabase for RootDatabase {}
impl<'a> Upcast<'a, dyn DefDatabase> for RootDatabase {
fn upcast(&self) -> &(dyn DefDatabase + 'a) { // now we can replace 'static with 'a
&*self
}
}
impl<'a> Upcast<'a, RootDatabase> for RootDatabase {
fn upcast(&self) -> &Self { // &Self is not a trait object, so no trait object lifetime is necessary
self
}
}
Edit:
It should be noted that this lifetime is not the lifetime of the reference to the trait object, which can be declared separately and is the reason for why the lifetime must be disambiguated with parenthesis.
impl<'a> Upcast<'a, dyn DefDatabase> for RootDatabase {
fn upcast<'b>(&'b self) -> &'b (dyn DefDatabase + 'a) { // 'b is elided
&*self
}
}
use once_cell::sync::OnceCell;
pub trait SomeTrait {}
pub struct Impl1 {}
impl SomeTrait for Impl1 {}
pub static GLOBAL_THING: OnceCell<Box<dyn SomeTrait>> = OnceCell::new();
pub fn main() {
GLOBAL_THING.set(Box::new(Impl1 {})).unwrap();
}
I'm getting this error and not sure how to interpret it's meaning or fix it.
error[E0599]: the method `unwrap` exists for enum `Result<(), Box<(dyn SomeTrait + 'static)>>`, but its trait bounds were not satisfied
--> src/main.rs:11:42
|
11 | GLOBAL_THING.set(Box::new(Impl1 {})).unwrap();
| ^^^^^^ method cannot be called on `Result<(), Box<(dyn SomeTrait + 'static)>>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`Box<dyn SomeTrait>: Debug`
An easy workaround is to just do if let Err() = GLOBAL_THING.set() {panic!(...)} instead of using unwrap(), but I'd like to understand what's going on here and fix if possible.
If you take a look at the unwrap method documentation you'll see that it's not defined for all Results, but only ones where E: Debug:
impl<T, E> Result<T, E>
where
E: Debug,
{
pub fn unwrap(self) -> T;
}
It needs the error type E to implement Debug so that the error can be printed if unwrapping fails.
The error message shows that the result type is Result<(), Box<(dyn SomeTrait + 'static)>>, so E = Box<(dyn SomeTrait + 'static)>. You can make this error type debuggable by having SomeTrait: Debug, which requires that any type that implements SomeTrait must also implement Debug.
pub trait SomeTrait: Debug {}
#[derive(Debug)]
pub struct Impl1 {}
Once you do this you'll hit the next error:
error[E0277]: `dyn SomeTrait` cannot be shared between threads safely
--> src/main.rs:11:1
|
11 | pub static GLOBAL_THING: OnceCell<Box<dyn SomeTrait>> = OnceCell::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn SomeTrait` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `dyn SomeTrait`
= note: required because of the requirements on the impl of `Sync` for `Unique<dyn SomeTrait>`
= note: required because it appears within the type `Box<dyn SomeTrait>`
= note: required because of the requirements on the impl of `Sync` for `once_cell::imp::OnceCell<Box<dyn SomeTrait>>`
= note: required because it appears within the type `once_cell::sync::OnceCell<Box<dyn SomeTrait>>`
= note: shared static variables must have a type that implements `Sync`
To fix this you'll also want to make the boxed trait object Send + Sync so that it can be shared across threads.
pub static GLOBAL_THING: OnceCell<Box<dyn SomeTrait + Send + Sync>> = OnceCell::new();
You can see the final result on the Playground.
I'm in a situation where I need to store away a function that implements a trait into a struct. Here is some reduced code
struct Node<T>{
compute_func: Box<dyn Fn(&[T]) -> T>
}
impl<T: Debug + 'static> OtherHoldingStruct<T> {
pub fn create_node<F: Fn(&[T]->T>(..., _compute_func: F) {
Node {
compute_function: Box::new(_compute_func),
//~~~~ the parameter type `impl Fn(&[T]) -> T` may not live long enough
//~~~~ ...so that the type `impl Fn(&[T]) -> T` will meet its required lifetime bounds rustc(E0310)
}
}
What I gather is that since I'm trying to accept a function type that takes a reference to a slice, the compiler is trying to create some assurances around how the lifetime of the reference to the slice will behave. What i'm not sure of is how to give it that ?
I considered adding a lifetime to create_node
impl<T: Debug + 'static> OtherHoldingStruct<T> {
pub fn create_node<'a, F: Fn(&'a [T]->T>(..., _compute_func: F) {
Node {
compute_function: Box::new(_compute_func),
//~~~~ expected a `std::ops::Fn<(&[T],)>` closure, found `impl Fn(&'a [T]) -> T`
}
}
which then seems to barf at not being able to match closures to the type.
The problem is not the slice reference — it's a lifetime requirement on the function type F itself. If you're going to store the function, then the function itself must be able to live for 'static (unless there's an explicitly permitted shorter lifetime).
The requirement actually in your code causing the compiler error appears because dyn Fn (or any other dyn) has an implicit + 'static bound if you don't specify a different lifetime. Thus, the bounds for F in create_node are Fn(&[T]) -> T but the bounds for compute_function are Fn(&[T]) -> T + 'static, creating the error you saw.
The fix is to add a 'static bound on F:
pub fn create_node<F: Fn(&[T]) -> T + 'static>(_compute_func: F) -> Node<T> {
// ^^^^^^^^^
This bound disallows passing, for example, a closure that captures a non-static reference, which has to be invalid anyway since Node could live indefinitely, unlike that reference.
I have this type:
struct Wrap<T>(Vec<T>);
I want to implement std::ops::Index and return references to trait objects. This was my first attempt (Playground):
use std::ops::Index;
use std::fmt::Display;
impl<T> Index<usize> for Wrap<T>
where
T: Display
{
type Output = Display;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
This doesn't work and leads to this error:
error[E0310]: the parameter type `T` may not live long enough
--> src/main.rs:13:9
|
7 | impl<T> Index<usize> for Wrap<T>
| - help: consider adding an explicit lifetime bound `T: 'static`...
...
13 | &self.0[index]
| ^^^^^^^^^^^^^^
|
note: ...so that the type `T` will meet its required lifetime bounds
--> src/main.rs:13:9
|
13 | &self.0[index]
| ^^^^^^^^^^^^^^
I think I know why this happens: type Output = Display is equivalent to type Output = Display + 'static as every trait object carries a lifetime bound which defaults to 'static.
So now I can just add the 'static bound to my parameter T, but this is over-constrained I think. I can easily implement such a method when not using an associated type:
impl<T> Wrap<T>
where
T: Display,
{
fn my_index(&self, index: usize) -> &Display {
&self.0[index]
}
}
No 'static bound needed, because now the signature desugars to:
fn my_index<'a>(&'a self, index: usize) -> &'a Display + 'a
Which makes sense: the trait object has to live for at least 'a. (Playground with all the code).
But can I make this work using associated types (like with the Index trait)? I have the feeling that this might work with generic associated types, but (a) I'm not sure and (b) they are not implemented yet.
One attempt is to attach a lifetime to the impl:
// Note: won't work.
impl<'a, T> Index<usize> for Wrap<T>
where
T: Display + 'a,
{
type Output = Display + 'a;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
However, the compiler will not accept it because 'a is not used.
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:7:6
|
7 | impl<'a, T> Index<usize> for Wrap<T>
| ^^ unconstrained lifetime parameter
There are several solutions suggested by the error code E0207, but since we cannot change the Index trait, the only acceptable solution is to make Wrap capture that unconstrained lifetime parameter:
use std::ops::Index;
use std::fmt::Display;
use std::marker::PhantomData;
struct Wrap<'a, T>(Vec<T>, PhantomData<&'a ()>);
// ^~ ^~~~~~~~~~~~~~~~~~~
impl<'a, T> Index<usize> for Wrap<'a, T>
where
T: Display + 'a,
{
type Output = Display + 'a;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
fn main() {
let w = Wrap(vec!['a', 'b'], PhantomData);
println!("{}", &w[0]); // prints "a"
let s = "hi".to_string();
let w = Wrap(vec![&s], PhantomData);
println!("{}", &w[0]); // prints "hi"
}
(Playground)
For sure, this will change your API and that extra lifetime will infect everywhere... If this is not acceptable, you could either
Not use the Index trait, introduce your own lifetime-sensitive trait instead (thus users will need to use w.my_index(i) instead of &w[i]); or
Set Output = Display + 'static, and exclude all transient types. Users will need to clone or use Rc.
Return a reference to T instead of returning a reference to a trait object and let the user cast to a trait object, or just let Rust implicitly infer from the context when to perform the cast:
use std::fmt::Display;
use std::ops::Index;
fn main() {
let w1 = Wrap(vec!['I', 'b']);
let s = "am".to_string();
let w2 = Wrap(vec![&s]);
let w3 = Wrap(vec![1, 2]);
let mut trait_store: Vec<Box<Display>> = Vec::new();
trait_store.push(Box::new(w1.index(0)));
trait_store.push(Box::new(w2.index(0)));
trait_store.push(Box::new(w3.index(0)));
for el in trait_store {
println!("{}", el);
}
}
struct Wrap<T>(Vec<T>);
impl<T> Index<usize> for Wrap<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
Hi I met the same problem as you. "Like &Index<usize, Output = Display>. This doesn't work with Index directly, but using Index in my question made it a bit easier."
I didn't find out whether the Rust releases some related features or not. But I figure out a rather foolish way to fulfill my demands.
This method only works when the structs which implement the trait are enumerable. Suppose that you have three structs Index1, Index2, Index3, they all implement the trait Index<usize, Output = Display>
Then we can simply wrap these structs by
pub enum Indices{
Index1(Index1),
Index2(Index2),
Index3(Index3),
}
And then implement the trait for the enum and all of its variants, there is an example for this:
rust - How do I implement a trait for an enum and its respective variants? - Stack Overflow
I have a structure that contains a value and I want to obtain a function that operates on this value:
struct Returner {
val: i32,
}
impl<'a> Returner {
fn get(&'a self) -> Box<Fn(i32) -> i32> {
Box::new(|x| x + self.val)
}
}
This fails compilation:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:7:18
|
7 | Box::new(|x| x + self.val)
| ^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 5:1...
--> src/main.rs:5:1
|
5 | impl<'a> Returner {
| ^^^^^^^^^^^^^^^^^
= note: ...so that the types are compatible:
expected &&Returner
found &&'a Returner
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<std::ops::Fn(i32) -> i32 + 'static>
found std::boxed::Box<std::ops::Fn(i32) -> i32>
This is because the closure borrows self, which is fine by me, because I don't intend to use the obtained function after the struct is destroyed. From what I've gathered so far, there's two ways to make it possible:
Use the move keyword. I don't want to use it because it will take ownership on the object, and want I to use it after it has returned this function.
Explicitly specify the lifetime of the closure to tell the compiler that it has the same lifetime as the struct it was called from.
I think that 2 is the correct way in my situation, but I've not been able to find out how to specify the closure's lifetime. Is there a direct way to do it or I've got it all wrong and it contradicts Rust lifetime logic?
In general, you can specify the lifetime of a boxed trait object by writing Box<Trait + 'a> and analogously for trait objects behind other kinds of pointers (if it's omitted, it defaults to 'static at least in the case of Box). So in this specific case you want the return type Box<(Fn(i32) -> i32) + 'a>.
However, when you do that you will see another error about self not living long enough. The reason is that (without move) the closure will capture a reference to the local variable self. The solution is to use move. This does not move the Returner object, it moves self which is a reference to the Returner object.
In summary:
struct Returner {
val: i32,
}
impl<'a> Returner {
fn get(&'a self) -> Box<Fn(i32) -> i32 + 'a> {
Box::new(move |x| x + self.val)
}
}
As said in an existing answer:
Add a lifetime that ties the lifetime of self to the lifetime of the returned value.
Move the reference to self into the closure.
Since Rust 1.26, you no longer need to return a boxed closure if you are only returning a single type. Instead, you can use impl Trait:
impl Returner {
fn get<'a>(&'a self) -> impl Fn(i32) -> i32 + 'a {
move |x| x + self.val
}
}
See also:
Why is adding a lifetime to a trait with the plus operator (Iterator<Item = &Foo> + 'a) needed?
What is the correct way to return an Iterator (or any other trait)?
Returning a closure from a function
Conditionally iterate over one of several possible iterators