I'm new to rust and I experience difficulties to develop my personal first project.
To get the essential my code looks like this:
pub trait MyTrait {
type Out: MyTrait;
fn foo(&self) -> Box<Self::Out>;
}
pub struct MyStruct<T: MyTrait>(Box<T>);
impl<T: MyTrait> MyTrait for MyStruct<T> {
type Out = Self <>;
fn foo(&self) -> Box<Self::Out> {
Box::new(self)
}
}
The error message I get is :
expected struct MyStruct<T> found reference &MyStruct<T>
I tried many things but I can't find how to return a box to self...
I have another question: actually MyTrait extends another trait and I have many struct that implement MyTrait so in my code I have many impl, one for each trait by struct and I find it really verbose, isn't it possible to implement all methods (from a trait and all its parents) at once (like in java) ? Or is there syntactic sugar to implement methods with closures ?
Thanks
Box needs to own self. You cannot pass a reference into it, it has to be the actual self object.
This works:
pub trait MyTrait {
type Out: MyTrait;
fn foo(self) -> Box<Self::Out>;
}
pub struct MyStruct<T: MyTrait>(Box<T>);
impl<T: MyTrait> MyTrait for MyStruct<T> {
type Out = Self;
fn foo(self) -> Box<Self::Out> {
Box::new(self)
}
}
Further remarks:
I'm unsure why you need that function, but it seems to me like you are trying to downcast from a boxed dyn trait to an actual type.
Sadly, this won't work this way. It's impossible for the compiler to figure out which type was the original type if your Box<dyn MyTrait> doesn't contain that information any more. That's why you need the Out associated type here, but you probably didn't yet realize that this means you can no longer store a Box<dyn MyTrait> object. It's now a Box<dyn MyTrait<Out = MyStruct>> object, which cannot be mixed with other MyTrait types any more.
If you really want to achieve that, there are several options. RTTI is one option, with the Any trait.
Another one would be a Visitor pattern, which could resolve this:
pub trait Visitor {
fn visit_mystruct(&mut self, s: &mut MyStruct);
}
pub struct MyVisitor;
impl Visitor for MyVisitor {
fn visit_mystruct(&mut self, s: &mut MyStruct) {
println!("Visited MyStruct: {:?}", s.0);
}
}
pub trait MyTrait {
fn visit(&mut self, visitor: &mut dyn Visitor);
}
pub struct MyStruct(i32);
impl MyTrait for MyStruct {
fn visit(&mut self, visitor: &mut dyn Visitor) {
visitor.visit_mystruct(self);
}
}
fn main() {
let mut obj: Box<dyn MyTrait> = Box::new(MyStruct(42)) as Box<dyn MyTrait>;
let mut visitor = MyVisitor;
// Here is no information any more about the actual type of `obj`.
// Visitor gets the type resolved again
obj.visit(&mut visitor);
}
Visited MyStruct: 42
A visitor pattern is especially useful in cases like tree structures, because it can be recursively applied to children. It is commonly used in compilers.
Another alternative would be to use an Enum instead of a Box<dyn Trait>.
Although those are all just based on assumptions now.
Related
I'm trying to use a trait object in a hashmap so I can call an update function.
This here is really the code I'm trying to write. I am pretty sure that I can change this code to get this to work the way that I want as-is, but I figured I can turn this into a learning opportunity because the Sized stuff is not quite clear to me.
let mut hm: HashMap<SomeEnum, Box<dyn SomeTrait>> = HashMap::new();
hm.entry(SomeEnum::Type1).and_modify(|b| b.some_other_func()).or_insert(/* HOW */ default());
But I don't really understand the Sized restrictions on trait objects or what Sized is (or why using Default as a Supertrait prevents the object from being Sized). If the entry does not exist in the hashmap, I would like to add the default version of that object to the entry.
Here's an reprex showing my issue.
use std::collections::HashMap;
#[derive(PartialEq, Eq, Hash)]
enum SomeEnum {
Type1,
Type2,
}
// SomeTrait is a subtrait of Default
// Because I want every type to implement Default
trait SomeTrait: Default {
fn new() -> Self {
Self {
..Default::default()
}
}
fn some_other_func(&self);
}
// SomeStruct implements Default and SomeTrait
struct SomeStruct {
foo: i32,
}
impl Default for SomeStruct {
fn default() -> Self {
SomeStruct { foo: 10 }
}
}
impl SomeTrait for SomeStruct {
fn some_other_func(&self) {}
}
fn main() {
let mut hm: HashMap<SomeEnum, Box<dyn SomeTrait>> = HashMap::new();
hm.entry(SomeEnum::Type1)
.and_modify(|b| b.some_other_func())
.or_insert(/* HOW */ default());
}
I cannot use a generic type instead of the trait object because I do/will have multiple implementations of this trait.
I have also tried creating a new trait that is a subtrait of both Default and the one I want:
trait AutoSomeType: SomeType + Default {}
trait SomeType {
fn new() -> Self
where
Self: Sized,
{
Self {
..Default::default()
}
}
fn some_other_func(&self);
}
I got here somehow based on a compiler recommendation, but I feel like this isn't on the right track to a solution.
I have a container type like this:
struct Container<T: Sized + MyTrait + Serialize> {
data: T,
key: String
}
wrapping this trait:
trait MyTrait {
fn do_something(&self) -> Something;
}
I have many concrete implementors of MyTrait:
struct S1 {}
impl MyTrait for S1 { ... };
... many kinds ...
struct S10{}
impl MyTrait for S10 { ... }
I have a higher level which should vend the appropriate implementation based on some decision logic (a factory of MyTrait types):
fn get_appropriate_impl(type_of_instance: SomeEnum ... ) -> Container<MyTrait> {
...choose appropriate implementation to return...
return match type_of_instance {
// each branch should return a different type
}
}
I get an error
Container<MyTrait> {
doesn't have a size known at compile-time
I've tried many variations:
Container<Box<MyTrait>>
Box<Container<MyTrait>>
Box<Container<Box<MyTrait>>
each has their own errors
How do I resolve this?
PS - I've also implemented Deref and DerefMut on Container:
impl<T: MyTrait > Deref for Container<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
You are trying to return a trait, not an object. The size of an implementation of a trait is not known at compile time (imagine, you implement MyTrait for u8 and u16, what size the return type would have?). The Sized bound does not help here (and it's implicit, too), because it only requires that T is Sized, but not MyTrait. Also, adding a bound to MyTrait: Sized does not help because it only requires, that the object, you implement MyTrait for, is sized, but it does not specify which size it may have.
This can be solved by either returning a concrete type, which is implementing MyTrait or wrapping the trait (e.g. in a Box). You are probably looking for the latter approach.
Returning a concrete type can be either done by adding a generic argument to the function:
fn get_appropriate_impl<T: MyTrait>() -> Container<T> {
...
}
or by using the impl Trait notation:
fn get_appropriate_impl() -> Container<impl MyTrait> {
...
}
However, if you don't know the return type beforehand, you probably want to store the object on the heap and return a pointer to that, e.g. by using Box, Rc, or Arc:
fn get_appropriate_impl() -> Container<Box<dyn MyTrait>> {
...
}
This requires you to implement MyTrait on Box<dyn MyTrait> as well, this can be done by implementing it on Box yourself:
impl MyTrait for Box<dyn MyTrait> {
fn do_something(&self) -> Something {
(**self).do_something()
}
}
If you know that you will only use Box for Container<T> you might want to encapsulate it there directly:
struct Container {
data: Box<dyn MyTrait>,
}
I am learning Rust and have run into the following problem, which is not obvious to me.
I saw a std::thread::spawn in the library, looked at the implementation, and saw that some type requires an implementation of the Send trait to be able to send something to another thread.
I'm trying to replicate the behavior with my own function and my own trait, but the compiler successfully compiles the code without complaining that the trait is not implemented for my types.
What am I missing?
pub trait SomeTrait {
fn bar(&self);
}
#[derive(Debug)]
struct StructWithoutTrait {
_data: Box<i32>
}
#[derive(Debug)]
struct StructWithTrait {
_data: Box<i32>
}
impl SomeTrait for StructWithTrait {
fn bar(&self) {}
}
fn foo<F, T>(f: F) -> T
where
F: FnOnce() -> T,
F: SomeTrait + 'static,
T: SomeTrait + 'static
{
f.bar();
f()
}
impl<F, T> SomeTrait for F
where
F: FnOnce() -> T,
T: SomeTrait
{
fn bar(&self) {}
}
fn main() {
let without_trait = StructWithoutTrait { _data: Box::new(1) };
let with_trait = StructWithTrait { _data: Box::new(2) };
let x = std::rc::Rc::new(1);
foo(move || {
println!("{:?}", without_trait);
println!("{:?}", x);
with_trait
});
}
Send is an auto trait. Auto-traits are somewhat like compiler-implemented; the steps of determining whether a type T implements an auto trait AutoTrait are the following:
If there is an explicit impl AutoTrait for T, then T always impls AutoTrait (note that because Send is an unsafe trait you need unsafe impl Send for T, but the general principle stays the same).
Otherwise, if there is a negative impl impl !AutoTrait for T, then T does not implement AutoTrait. Note that this is an error to have both positive and negative impl of the same trait for the same type.
Otherwise, if any of the fields of T does not implement AutoTrait, T does not implement it either. For example, if T is defined as struct T(U);, and there's impl !AutoTrait for U, then T does not implement AutoTrait.
Otherwise, T implements AutoTrait.
Both auto traits and negative impls are highly unstable features, and not intended to use as of now outside of the standard library. If you really want, you can, although because the compiler must be able to implement the trait automatically, it cannot contain any associated item (methods, associated types, associated consts). If you remove the bar() method, this is how your code will look like:
#![feature(auto_traits, negative_impls)]
pub auto trait SomeTrait {}
#[derive(Debug)]
struct StructWithoutTrait {
_data: Box<i32>
}
impl !SomeTrait for StructWithoutTrait {}
#[derive(Debug)]
struct StructWithTrait {
_data: Box<i32>
}
fn foo<F, T>(f: F) -> T
where
F: FnOnce() -> T,
F: SomeTrait + 'static,
T: SomeTrait + 'static
{
f()
}
fn main() {
let without_trait = StructWithoutTrait { _data: Box::new(1) };
let with_trait = StructWithTrait { _data: Box::new(2) };
let x = std::rc::Rc::new(1);
foo(move || {
println!("{:?}", without_trait);
println!("{:?}", x);
with_trait
});
}
Playground.
I am pretty sure that is compiler behaviour:
A closure is Send if all variables captured by non-unique immutable reference are Sync, and all values captured by unique immutable or mutable reference, copy, or move are Send.
~ https://doc.rust-lang.org/reference/types/closure.html
It is therefore not something you can really implement right now with how closure types are completely untransparent
Currently Send is handled specially by the the compiler. Quoting from the documentation:
This trait is automatically implemented when the compiler determines it’s appropriate.
There are plans to move the implementation fully into the standard library (tracking issue), which should make it possible to have similar user-defined marker traits. There is a chance that when this feature gets stabilized you might be able to write:
auto trait SomeTrait {}
struct StructWithTrait {}
struct StructWithoutTrait {}
impl !SomeTrait for StructWithoutTrait {}
and get a behaviour similar to Send.
I have a trait object, and I want to know the concrete object that it points to, but I cannot work out how to get the concrete object.
What I want is something like the following:
trait MyClonable {
/** copy from another MyClonable */
fn my_clone_from(&mut self, other: &Self)->Result<(), MyError>;
}
impl MyClonable for SomeType {
fn my_clone_from(&mut self, other: &MyClonable)->Result<(), MyError> {...}
}
So that I can say something like:
let mut new_thing = SomeType::new();
new_thing.my_clone_from(&old_thing)?;
Then the new_thing will contain a sort-of copy of the old_thing, unless old_thing is of an unexpected type, in which case it should return an error.
But Rust will not let me get something like an Option<&SomeType> from a MyClonable.
You cannot. The trait object only gives you access to the trait methods. You would need to manually specify which concrete type to downcast to as described in this QA: How to get a reference to a concrete type from a trait object?.
Then, you could try downcasting to each of your known types until one of them succeeds but that is dirty.
Instead, using generics would be a better fit:
trait MyClonable<T> {
fn my_clone_from(&mut self, other: &T);
}
And now you can implement this trait for all your supported types:
impl MyClonable<u32> for i32 {
fn my_clone_from(&mut self, _other: &u32) { }
}
impl MyClonable<Tomato> for i32 {
fn my_clone_from(&mut self, _other: &Tomato) { }
}
I'm fighting with lifetimes again. Or actually, I kinda won the fight but I'm not sure if the outcome is the intended way to handle it.
Say I have a struct with two lifetimes: Inner<'a, 'b>. Now I want to write a trait that defines a new(inner: &Inner) -> Self method. The implementer should be free to store the reference to Inner internally and define other methods to work on it.
I came up with this (it works!) but I have a couple of questions
struct Inner<'a, 'b>{
foo: &'a str,
bar: &'b str
}
trait Worker<'data, 'a, 'b> {
fn new (inner: &'data Inner<'a, 'b>) -> Self;
fn work_with_inner () { println!("works on inner");}
}
struct SomeWorker<'inner, 'a:'inner, 'b:'inner> {
inner: &'inner Inner<'a, 'b>
}
impl<'data, 'a, 'b> Worker<'data, 'a, 'b> for SomeWorker<'data, 'a, 'b> {
fn new (inner: &'data Inner<'a, 'b>) -> Self {
SomeWorker {
inner: inner
}
}
}
fn main () {
}
Playpen: http://is.gd/A3ol4w
in terms of lifetimes, can this be simplified? In particular, I was wondering if the trait really needs to define all those lifetimes or if there's a way to only define them on the struct?
if there's no way to omit the lifetimes on the trait does that mean it's a best practice to specify all possible lifetimes on a trait to have the most flexibility for the implementer? I mean, if the SomeWorker struct would not want to store the reference to Inner, the whole thing, including the trait, could be much simpler.
See, no lifetimes at all.
struct Inner<'a, 'b>{
foo: &'a str,
bar: &'b str
}
trait Worker {
fn new (inner: &Inner) -> Self;
fn work_with_inner () { println!("works on inner");}
}
struct SomeWorker;
impl Worker for SomeWorker {
fn new (inner: &Inner) -> Self {
SomeWorker
}
}
fn main () {
}
Playpen: http://is.gd/NzigjX
This is why I'm asking myself if as a trait author I should assume that all methods that take references may end up being stored on a field by the trait implementer and therefore I need to specify all the lifetimes on the trait to make that possible for implementors.
There is no one-size-fits-all solution. As a trait author, you have to think about what you are attempting to do and what you want to achieve.
If you want the ability to correlate a values lifetime with the lifetime parameters of a struct, then you must put the lifetime on the trait. This would generally be done because your trait has multiple methods that are expected to operate on the same value with lifetimes. This might something like a getter / setter pair. In some code I have written, I'm passing in &str references that I hold onto for a while before "finalizing" them. If you need to store the reference for any reason, then you will need to have lifetimes on the trait.
In your case, you have a constructor method that needs to know of the lifetimes if the struct does. You can separate that function from the rest of the trait, if it's truly distinct. In your example, the work_with_inner method doesn't accept a self argument, so that would be very distinct. If you used self but didn't need to interact with the lifetimes from Inner, it can still help:
trait WorkerBuilder<'a, 'b> {
fn new(inner: Inner<'a, 'b>) -> Self;
}
trait Worker {
fn do_work(&self);
}
#[derive(Debug)]
struct Inner<'a, 'b>{
foo: &'a str,
bar: &'b str,
}
// This does track `Inner`
#[derive(Debug)]
struct SomeWorker<'a, 'b>(Inner<'a, 'b>);
impl<'a, 'b> WorkerBuilder<'a, 'b> for SomeWorker<'a, 'b> {
fn new(inner: Inner<'a, 'b>) -> SomeWorker<'a, 'b> {
SomeWorker(inner)
}
}
impl<'a, 'b> Worker for SomeWorker<'a, 'b> {
fn do_work(&self) { println!("Doing work, {:?}", self.0) }
}
// This doesn't track `Inner`
#[derive(Debug)]
struct DumbWorker;
impl<'a, 'b> WorkerBuilder<'a, 'b> for DumbWorker {
fn new(inner: Inner<'a, 'b>) -> DumbWorker {
DumbWorker
}
}
fn main () {}
You'll see I also applied one thing that you can do to reduce the number of lifetimes. If you have a struct that is just references (or references and other small Copy types), there is no need to pass a reference to that struct. References are copyable, and tracking the lifetime of the containing struct isn't useful.
Editorial — I don't feel like "constructor" methods are generally useful in a trait. You often want to provide a different set or parameters, which is why you have different types in the first place. Perhaps your real code is using something other than a constructor in the trait though.