I have a design issue, when using something like :
trait MyTrait<K: OtherTrait> { ... }
impl<K: OtherTrait, M: MyTrait<K>> AnyTrait for M { ... }
I cannot implement trait for this trait due to E207 error ("the type parameter K is not constrained by the impl trait, self type, or predicates").
Finding no way to get rid of this error, I apply this not-so-good-looking workaround (verbose and struct with no intrinsic value):
use std::fmt;
use std::marker::PhantomData;
pub trait MyTrait<K: fmt::Display> {
fn get_some_k(&self) -> Option<K>;
}
/* // This is my target impl but results in E207 due to K not constrained
impl<K: fmt::Display, S: MyTrait<K>> fmt::Display for S {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.get_some_k().unwrap())
}
} */
pub struct Ugly<'a, K: fmt::Display, S: 'a + MyTrait<K>>(&'a S, PhantomData<K>);
impl<'a, K: fmt::Display, S: MyTrait<K>> fmt::Display for Ugly<'a, K, S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0.get_some_k().unwrap())
}
}
fn main() { }
I think there should be some nicer way to implement a trait for this kind of parameterized trait.
I did not find good example in std (for instance no Display implementation in traits with associated type like Iterator)?
Here’s an implementation using associated types (which means that you can only implement MyTrait for one K per type):
use std::fmt;
pub trait MyTrait {
type K: fmt::Display;
fn get_some_k(&self) -> Option<Self::K>;
}
impl<S: MyTrait> fmt::Display for S {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.get_some_k().unwrap())
}
}
fn main() { }
However, when clarified like this it becomes clear that this approach won’t work either, because you’re implementing Display for all types that implement MyTrait—types that could have their own Display implementation. This is forbidden, and so you get E0210:
error: type parameter S must be used as the type parameter for some local type (e.g. MyStruct<T>); only traits defined in the current crate can be implemented for a type parameter [E0210]
Wrapping it in something—like your Ugly did—is the only way to allow such an implementation. Or implement a trait in your own crate rather than one in someone else’s (like Display is).
Related
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.
I am trying to avoid lifetimes because I still don't have a good understanding of the concept. I am reading this wonderful article and it clarifies many misunderstandings. Although I am not sure I can solve the problem.
I know how to implement iterable collection on dyn. Playground:
use std::collections::HashMap;
pub trait Enumerable {
fn elements<'a, 'b>(&'a self) -> Box<dyn Iterator<Item = (i32, &String)> + 'b>
where
'a: 'b;
}
#[derive(Debug)]
struct Container {
pub map: HashMap<i32, String>,
}
impl Enumerable for Container {
fn elements<'a, 'b>(&'a self) -> Box<dyn Iterator<Item = (i32, &String)> + 'b>
where
'a: 'b,
{
Box::new(self.map.iter().map(|el| (*el.0, el.1)))
}
}
My attempt to implement the same code without dyn. Playground:
use std::collections::HashMap;
pub trait Enumerable<'it, 'it2, It>
where
It: Iterator<Item = &'it2 (i32, &'it String)>,
'it: 'it2,
{
fn elements<'a, 'b>(&'a self) -> It
where
'a: 'b;
}
#[derive(Debug)]
struct Container {
pub map: HashMap<i32, String>,
}
impl<'it, 'it2> Enumerable<'it, 'it2, core::slice::Iter<'it, (i32, &String)>> for Container {
fn elements<'a, 'b>(&'a self) -> core::slice::Iter<'a, (i32, &'b String)>
where
'a: 'b,
{
self.map.iter().map(|el| (*el.0, el.1))
}
}
I was thinking about using impls but there is a restriction on using it in a trait. What is wrong with the code? What other useful articles can you recommend?
Apart of the fact that I don't think you need two separate lifetimes 'a and 'b, your first code example already looks quite promising.
Then, once you have only one lifetime, Rust can figure out lifetimes without any annotations:
use std::collections::HashMap;
pub trait Enumerable {
fn elements(&self) -> Box<dyn Iterator<Item = (i32, &String)> + '_>;
}
#[derive(Debug)]
struct Container {
pub map: HashMap<i32, String>,
}
impl Enumerable for Container {
fn elements(&self) -> Box<dyn Iterator<Item = (i32, &String)> + '_> {
Box::new(self.map.iter().map(|el| (*el.0, el.1)))
}
}
I know this is an XY-problem answer, but maybe it helps anyway. Your main reasoning behind not using dyn was to not deal with lifetimes, so I thought this might be relevant.
There is a solution to the original problem with GAT and TAIT which are not part of stable channgel for today.
Solution is
mod mod1 {
pub trait Enumerable {
type It<'it>: Iterator<Item = (i32, &'it String)>
where
Self: 'it;
fn elements(&self) -> Self::It<'_>;
}
}
//
impl mod1::Enumerable for Container {
type It<'it> = impl Iterator<Item = (i32, &'it String)>;
fn elements(&self) -> Self::It<'_> {
self.map.iter().map(|el| (*el.0, el.1))
}
}
Full solution
There are alternative solutions, but this one works even if the trait is not part of your crate.
Also, I should note, that if possible to avoid using lifetimes you can implement IntoIterator for your &Container:
impl< 'it > IntoIterator for &'it Container
{
type Item = ( &'it i32, &'it String );
type IntoIter = std::collections::hash_map::Iter< 'it, i32, String >;
fn into_iter( self ) -> Self::IntoIter
{
self.map.iter()
}
}
Full solution of a tweaked problem
Because the lifetime is dropped that works even on stable Rust.
Most probably you want to have your own InotIterator-like trait, especially if there is more than a single way how can you iterate your container, but if not you can simply implement standard IntoIterator for reference.
In rust, I want in my impl fmt::Display for MainStruct, to be able to print another struct.
#[derive(Clone, Default)]
pub struct MainStruct {
pub child: Option<ChildStruct>
}
#[derive(Clone, Default)]
pub struct ChildStruct {
pub field: String
}
impl std::fmt::Display for MainStruct {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "MainStruct: child:{}", self.child)
}
}
impl std::fmt::Display for ChildStruct {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "ChildStruct: field:{}", self.field)
}
}
I have tried with the default {} formatter, and with the {:?} formatter, but without any success.
The Problem is that Option<T> has not implemented the Display trait. So you have to get the value out of the option. The easiest to do so is .unwrap(). This however panics if the option is None. (other methods for unpacking are expect, match, …)
If you use .unwrap() the value is moved out of the Option. So the Option would now be invalid as it would not contain anything anymore. The compiler prevents this with an error cannot move out of 'self.child'.
So what you actually want is a reference that does not consume the child. So you want &T or &mut T from the Option. You can do that by using the .as_ref() to convert Option<T> to Option<&T>. Then if you do .unwrap() on that the compiler wont complain anymore as you just copy a &T pointer.
so your code compiles if you change the following:
impl std::fmt::Display for MainStruct {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "MainStruct: child:{}", self.child.as_ref().unwrap())
}
}
Since Option does not implement Display, you have to write some logic yourself to handle two possible cases. The simplest way might be to just match on the Option explicitly:
impl std::fmt::Display for MainStruct {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "MainStruct: child: ")?;
match self.child.as_ref() {
Some(child) => write!(f, "Some({})", child),
None => write!(f, "None"),
}
}
}
Here's the playground with a short test case.
I have some code which returns a trait object of type MyTrait so that it can return one of several different structs. I would like to implement the Display trait for the trait object so that I can print the object, with the details delegated to the various structs as they each need their own custom formatters.
I can achieve this by including a formatting method as part of the MyTrait definition, and then implementing Display for MyTrait and delegating - like this:
trait MyTrait {
fn is_even(&self) -> bool;
fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
}
impl fmt::Display for MyTrait {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.my_fmt(f)
}
}
However, I already have the Display trait implemented for each of the structs which implement MyTrait. This means I end up with two methods for each struct which do the same thing - the fmt() method to satisfy the Display trait directly on the struct, and the my_fmt() method which is called by the code above. This seems clumsy and repetitive. Is there a simpler way to do it?
Here's a complete example program which illustrates the point. It's a little longer than I would have liked (it's based on the answer to my previous question Calling functions which return different types with shared trait and pass to other functions), but I couldn't think of a simpler way to illustrate the point. Of course, in this toy example the structs and the fmt functions are very simple; in my real application they are more complex.
use std::fmt;
trait MyTrait {
fn is_even(&self) -> bool;
fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
}
struct First {
v: u8,
}
struct Second {
v: Vec<u8>,
}
impl MyTrait for First {
fn is_even(&self) -> bool {
self.v % 2 == 0
}
fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.v)
}
}
impl MyTrait for Second {
fn is_even(&self) -> bool {
self.v[0] % 2 == 0
}
fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.v[0])
}
}
fn make1() -> First {
First { v: 5 }
}
fn make2() -> Second {
Second { v: vec![2, 3, 5] }
}
// Implement Display for the structs and for MyTrait
impl fmt::Display for First {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.v)
}
}
impl fmt::Display for Second {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.v[0])
}
}
impl fmt::Display for MyTrait {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.my_fmt(f)
}
}
fn requires_mytrait<T: MyTrait + ?Sized>(v: &&T) {
println!("{:?}", v.is_even());
}
fn main() {
for i in 0..2 {
let v1;
let v2;
let v = match i {
0 => {
v1 = make1();
println!("> {}", v1); // Demonstrate that Display
// is implemented directly
// on the type.
&v1 as &MyTrait
}
_ => {
v2 = make2();
println!("> {}", v2); // Demonstrate that Display
// is implemented directly
// on the type.
&v2 as &MyTrait
}
};
requires_mytrait(&v);
println!("{}", v); // Here I print the trait object
}
}
Can anyone suggest a simpler, cleaner way to do this?
You can make Display a supertrait of MyTrait.
trait MyTrait: fmt::Display {
fn is_even(&self) -> bool;
}
This will make trait objects of MyTrait be Display. This only works if you expect all implementors of MyTrait to implement Display, but that was also the case in your previous solution.
I'm trying to write an extension trait that allows me to move any value of type T into any Box<B>, where Box<T> can be coerced into Box<B>. My first attempt is the following:
trait IntoBox<B: ?Sized> {
fn into_box(self) -> Box<B>;
}
impl<T, B: ?Sized> IntoBox<B> for T
where
Box<T>: Into<Box<B>>,
{
fn into_box(self) -> Box<B> {
Box::new(self).into()
}
}
fn main() {
// Ok
let _: Box<u32> = 42.into_box();
// Error: the trait bound `std::boxed::Box<std::fmt::Display>:
// std::convert::From<std::boxed::Box<&str>>` is not satisfied
let _: Box<std::fmt::Display> = "Hello World".into_box();
}
This code works for regular boxes, but not trait objects. I suspect Into is the wrong bound here. What should I use instead?
Edit: As explained in the answer to this question, this problem can be solved with respect to any number of concrete types T by providing a blanket impl for T: Unsize<U>. However this does not work in the generic case because the impls would be conflicting:
impl<T, B> IntoBox<B> for T
where
Box<T>: Into<Box<B>>,
{
fn into_box(self) -> Box<B> {
Box::new(self).into()
}
}
impl<T, B: ?Sized> IntoBox<B> for T
where
B: std::marker::Unsize<T>
{
fn into_box(self) -> Box<B> {
Box::new(self)
}
}