#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
impl Copy for Point {}
impl Clone for Point {
fn clone(&self) -> Point {
*self
}
}
When I only implement Copy, Rust tells me I need to implement Clone. When I only implement Clone, Rust tells me Point can be moved.
My question is, I have never implemented anything, This code is a bit like a circular dependency, but it works? Why?
TL;DR: Copy requires Clone for convenience and Clone on a Copy type is usually implemented using a copy.
The Rust compiler will routinely have to do bit-wise copy of your data. But there are two cases:
If the type does not implement Copy, the original instance isn't usable anymore, your data has moved.
If the type does implement Copy, the compiler knows that it's perfectly safe to continue using the original instance together with the new instance.
The Copy trait does not change the fact that the compiler will only automatically do bit-wise copies: It is a marker trait with no methods. Its job is only to tell the compiler “it's OK to continue using this after a bit-wise copy”.
The Clone trait isn't that special: It's a regular trait with a method that can do whatever you want it to do. The compiler never uses the Clone trait automatically and doesn't care about what it actually does. However it is clearly intended to create a clone of an instance, so it is perfectly normal to:
expect Copy types to implement Clone. After all, Copy is a more strict version of Clone. This is why Copy: Clone and you have to implement Clone on a Copy type.
expect Clone on a Copy type to be dumb and only perform a bit-wise copy. You wouldn't want two different semantics here, that would be very confusing. This is why clone is implemented with a simple *self in your example: This dereferences self, which causes a bit-wise copy.
It is however very uncommon to implement those trait manually, and most of the time, you'll just go with derive:
#[derive(Copy, Clone, Debug)]
struct Point {
x: i32,
y: i32,
}
Related
This question already has an answer here:
Can I get a trait object of a multi-trait instance without using a generic type?
(1 answer)
Closed 10 months ago.
In rust I would like to have a vec containing items which implement 2 traits. However when I try to implement it like so, I get the error only auto traits can be used as additional traits in a trait object:
let mut v : Vec<Box<dyn MyTrait + std::fmt::Display>> = Vec::new();
FairPlay, I read the error message in full and defined a Trait which combines the two:
pub trait FormattableDoer: std::fmt::Display + MyTrait{}
The have a Vec of Boxes to that:
let mut v: Vec<Box<dyn FormattableDoer>> = Vec::new();
However the compiler can't seem to detect that my struct has implemented those things separately and I get the error the trait bound MyStruct: FormattableDoer is not satisfied.
I read about using a trait alias, but that's not in stable so I'd rather not use it.
Is this possible in rust? It seems like a common thing to want to do and I'm surprised that the answer isn't simple (or maybe it is and I have missed it!). I'm also thinking that maybe I have approached the problem all wrong and I'm attempting to do something in an 'non rusty' way. If that's the case, what is the preferred way of having a vector of things which are displayable and have some other trait?
Playground with a MWE and a use case.
You're almost there. You need a marker trait that implements both parents, as you've already done
pub trait FormattableDoer: std::fmt::Display + MyTrait {}
Then you need a blanket implementation which takes those two traits to your new trait.
impl<T: std::fmt::Display + MyTrait> FormattableDoer for T {}
Now everything that implements std::fmt::Display and MyTrait will implement FormattableDoer automatically, and since FormattableDoer is a single trait, it can be used as a trait object.
Then just use Box<dyn FormattableDoer> like you've already tried.
You still need to implement FormattableDoer for your struct. In the playground you posted, you're not doing that. Simply add
impl FormattableDoer for MyStruct {}
and you should be all done.
No user-defined traits are auto-implemented, even if they contain no methods or associated types.
The following code will not compile unless Copy and Clone traits are derived in the enum. Why is this a requirement given that the enum is basically an i8 and according to the documentation, integers automatically implement the Copy trait? Related to this, since the size of MyEnum should be well known at compile time, shouldn't it go onto the stack? Doesn't the Clone trait imply that it goes on the heap?
#[derive(Debug, Copy, Clone)]
#[repr(i8)]
enum MyEnum {
Some1,
}
fn main() {
let x = MyEnum::Some1;
let y = x;
println!("x={:?} y={:?}", x, y);
}
Clone has nothing to do with the heap. Clone does not imply heap-allocated for any type, be they structs, enums, and whether they have a #[repr] attribute or not. Clone is just a normal trait.
And traits aren't implemented automatically, ever, because when writing a library, this would be an implicit part of your public interface. That is, an type could be implicitly, and unexpectedly, Clone without the library author intending to make it Clone. This limits how the type could change in the future, and the library author might inadvertently break their public interface by changing the content of the type and losing that implicit trait implementation. Rust always prefers explicitness over hidden things.
https://doc.rust-lang.org/std/borrow/trait.ToOwned.html
What does this mean?
But Clone works only for going from &T to T.
Could you please explain and give an example.
Clone is the way to go from a shared reference to owned version. Consider e.g. Rc. <Rc as Clone>::clone() takes &Rc and produces Rc.
Now suppose you want to impl Clone for str. The clone() method will need to take &str and return str. But you cannot return str, since it's unsized - the compiler cannot know how much memory to save.
Instead, it needs to return String which is the owned version of str. But it cannot with Clone, since Clone hardcodes the return type to be equal to the input type.
This is the gap ToOwned fills. It provides a way to go from shared to owned versions, for things where the shared and owned versions are not of the same type.
ToOwned is thus a superset of Clone (indeed, every type that impls Clone also impls ToOwned by this blanket implementation).
I was writing a library for a generic Box<T> and on one part of the code I needed to clone the Box<T>, so I did something like this:
impl<T> OnTheFlySwap<T>
where
T: ?Sized + Send + Sync, Box<T>: Clone
{
I added Box<T>: Clone thinking this is not a big deal, because only objects that explicitly prohibits Box<T>: Clone would have a problem. But no, apparently if the object does not explicitly implements Box<T>: Clone then I have a problem, because this is the official impl Clone for Box:
impl<T, A> Clone for Box<T, A> where
T: Clone,
A: Allocator + Clone,
It requires T to be Clone. Why? Wouldn't every Box<T> be Clone, since cloning a Box requires no time? If an object does not want its box to be clone then it could implement !Clone for it, but the default should be impl Clone for Box<T> for any T.
A Box<T> in Rust represents a box which owns a T. If you could clone a Box and get a second box pointing to the same T, then which one would own the T value? Box isn't just Rust's version of C++ pointers; it represents a concept of ownership that a language like C++ doesn't enforce.
As an exercise, consider trying to write the function you're suggesting for Box::clone yourself. Its signature would be
fn my_clone<T>(value: &Box<T>) -> Box<T> { ... }
Try writing a function with that signature without dipping into unsafe. The compiler will let you know pretty quickly what went wrong.
The only safe way to clone a box is to clone everything inside of the box as well, and that requires T : Clone.
I have the following code:
pub trait MyTrait {
pub fn do_something(&self);
}
If I want a struct A to have a field a that implements the trait MyTrait, there are 2 options:
pub struct A<'a> {
a: &'a MyTrait
}
or
pub struct A {
a: Box<MyTrait>
}
But on Difference between pass by reference and by box, someone said:
Really, Box<T> is only useful for recursive data structures (so that
they can be represented rather than being of infinite size) and for
the very occasional performance optimisation on large types (which you
shouldn’t try doing without measurements).
Unless A implements MyTrait, I'd say A is not a recursive data structure, so that makes me think I should prefer using a reference instead of a box.
If I have another struct B that has a reference to some A object, like this:
pub struct A<'a> {
a: &'a MyTrait
}
pub struct B<'a, 'b: 'a> {
b: &'a A<'b>
}
I need to say that 'b is larger than 'a, and according to the documentation:
You won't often need this syntax, but it can come up in situations
like this one, where you need to refer to something you have a
reference to.
I feel like that's a bad choice too, because the example here is really simple and probably doesn't need this kind of advanced feature.
How to decide whether I should use a reference or a box then?
Unfortunately, the quote you used applied to a completely different situation.
Really, Box<T> is only useful for recursive data structures (so that they can be represented rather than being of infinite size) and for the very occasional performance optimisation on large types (which you shouldn’t try doing without measurements).
Is speaking about using either of MyEnum or Box<MyEnum> for data members:
it is not comparing to references,
it is not talking about traits.
So... reset your brain, and let's start from scratch again.
The main difference between Box and a reference is ownership:
A Box indicates that the surrounding struct owns the piece of data,
A reference indicates that the surrounding struct borrows the piece of data.
Their use, therefore, is dictated by whether you want ownership or borrowing, which is a situational decision: neither is better than the other in the same way that a screwdriver and a hammer are not better than the other.
Rc (and Arc) can somewhat alleviate the need to decide, as they allow multiple owners, however they also introduce the risk of reference cycles which is its own nightmare to debug so I would caution over overusing them.