This question already has answers here:
Is it possible to add your own derivable traits, or are these fixed by the compiler?
(2 answers)
Closed 5 years ago.
I have a struct like this
#[derive(CustomTrait)]
struct Sample {
v: Vec<u8>,
}
and my trait goes like this
trait CustomTrait {...}
Can I do the above stuff? It threw an error for me.
I want something similar to the Clone trait. Is this possible with Rust?
#[derive(Foo, Bar)] is sugar for #[derive_Foo] #[derive_Bar], so it is possible to implement your own decorator attribute in the same way as #[derive_Clone] is, but this requires you to write a compiler plugin, which is not a stable part of Rust and will not be stable in 1.0 (and will thus be unavailable in the stable and beta channels).
There is a little documentation on such matters in the book, but not much; you’re largely on your own with it.
Bear in mind that what you can actually do at that stage is limited; you have access to the struct definition only, and know nothing about the actual types mentioned. This is a good fit for all of the traits for which #[derive] support is built in, but is not for many other traits.
No, you can't. derive instructs the compiler to provide a basic implementation of the trait. You can't expect the compiler to magically know how to implement a user-defined trait.
You can only use derive with these traits (taken from http://rustbyexample.com/trait/derive.html):
Comparison traits: Eq, PartialEq, Ord, PartialOrd
Serialization: Encodable, Decodable
Clone, to create T from &T via a copy.
Hash, to compute a hash from &T.
Rand, to create a random instance of a data type.
Default, to create an empty instance of a data type.
Zero, to create a zero instance of a numeric data type.
FromPrimitive, to create an instance from a numeric primitive.
Debug, to format a value using the {:?} formatter.
NOTE: Apparently this was proposed and is being discussed here
Related
The rust book says:
We can also implement Summary on Vec<T> in our aggregator crate,
because the trait Summary is local to our aggregator crate.
https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type
If my package uses another crate from crates.io, like rand, and rand implements a trait on a type in the standard library, like Vec<T>, will my code be able to see those methods?
I know there's a restriction where a trait has to be in scope for you to use its methods. If rand implemented a custom trait on Vec<T>, and I tried to use one of the methods in that trait within my crate, would the compiler tell me that I need to import that trait from rand before using those methods, or would it tell me that the methods don't exist? If it's the former, if I import the trait from rand, can I then use those methods on Vec<T>?
From my experimentation, if a crate implements a trait on a foreign type, that trait is accessible using the normal rules (that is, in order to call methods of that trait, you must bring it in into scope, but otherwise, nothing special is required). You don't need to do anything else.
For example, consider the crate serde, which provides facilities to serialize and deserialize data. It provides the traits Serialize and Deserialize, which allow data structures to define how they are serialized and deserialized into various formats. Additionally, it provides implementations of those traits for many built-in and std types (see here and here). I made a quick experiment here, and my code can use those traits without me having to do anything extra (in fact, as you'll see, since I never directly use those traits, I don't even have to bring them into scope).
So, to the best of my knowledge, the answer to your question is yes, your code can use a trait implemented by rand for Vec<T>. All you need to do is import that trait from rand.
Traits are used to group some functions to be implemented from a struct, but is it possible to access struct fields from within the trait?
I could imagine declaring fields inside the trait so that the fields are abstracted as well. I haven't found such a syntax; is there any other solution? Otherwise, it wouldn't be possible to have non-static methods using a trait, would it?
I know object oriented programming from C# and I'm playing around with Rust, trying to adapt the OOP functionality I already know from C#.
This sounds like you're misunderstanding how traits work. Traits can't have fields. If you want to provide access to a field from a trait, you need to define a method in that trait (like, say, get_blah).
If you're asking whether you can access fields of a struct from within that struct's implementation of a trait, then yes. The struct knows it's own type, so there's no problem.
trait Pet {
fn is_smelly(&self) -> bool;
}
struct Dog {
washed_recently: bool,
}
impl Pet for Dog {
fn is_smelly(&self) -> bool {
!self.washed_recently
}
}
If you're writing a default implementation of a trait (i.e. defining a method body within the trait), then no, you can't access fields. A default implementation can only use methods that are defined on the trait or in a super trait.
It would be useful to define fields in a trait's default implementation, so a struct implementing the trait would always have the same fields.
Apparently, the Rust team thinks the same but it is still a work in progress according to this RFC. It's a big change and it has been postponed, so I think the short answer is: you can't do it yet, but you might be able to do it in the future.
For now, you'll have to make do with less powerful traits.
You can make accessor function in default trait implementation, that must return field value/ref in child implementations, returning default value. Use it in other fn's in default implementation, and redefine accessor's in child implementation. Default implementation fn's will use redefined accessors as it's virtual fn's.
I just came across the problem of implementing a trait I do not own for a type I do not own. Then I googled the exact How do I implement a trait I don't own for a type I don't own? question.
The thing that confused me is the motivation behind such restriction. I came from Scala where it is possible to have an external typeclass instance for an external type.
Why does Rust restrict that?
I just read the Rust Book's chapter about implementing traits and, as #AlexLarionov suggested in the comment that it would be impossible to choose an appropriate implementation:
But we can’t implement external traits on external types. For example,
we can’t implement the Display trait on Vec<T> within our aggregator
crate, because Display and Vec<T> are defined in the standard library
and aren’t local to our aggregator crate. This restriction is part of
a property of programs called coherence, and more specifically the
orphan rule, so named because the parent type is not present. This
rule ensures that other people’s code can’t break your code and vice
versa. Without the rule, two crates could implement the same trait for
the same type, and Rust wouldn’t know which implementation to use.
As Alexey Larionov explains in the comments, if two crates could implement a trait for the same struct there would be a conflict of which trait implementation to use. With this restriction, Rust guarantees that every (struct, trait) pair will have at most one implementation across all crates.
If you find yourself needing to implement an external trait for an external struct you can leverage the Rust New Type Idiom.
By wrapping an external struct in a new type you are able implement any external trait on that new type.
While the new type won't be the same as the external struct, you can reference that wrapped type with the .0 syntax, as explained in the New Type Idiom documentation.
This question already has answers here:
Is there any way to restrict a generic type to one of several types?
(2 answers)
Closed 3 years ago.
We can restrict a type to one or more traits by where clause.
My questions are:
Is it possible to restrict a type to just primitive number types?
How?
No.
To use a parametric type, you need the trait to define the valid operations you want to call on it. So you need a trait (or more) with all the operations you want to call.
The “primitive” types in Rust are not special in any way. They define their operators via the traits from std::ops (though obviously using compiler intrinsics) just like any “non-primitive” numberic types.
In fact, the boundary between “primitive” and “non-primitive” numeric types is even somewhat blurred, since for targets that lack an FPU, the standard library may be implementing floating point types in code, and in Rust it can do it transparently to the user.
So really, there is no such thing as primitive number types. Number types are defined by providing whatever operators you need to call. So just restrict your type by the std::ops traits.
Since primitives are not trait types you cannot use as boundary to restrict a generic type. But you can directly implement for a specific type:
struct Struct<T>(T);
trait Printer {
fn print(&self);
}
impl Printer for Struct<i32> {
fn print(&self) {
println!("Printing for i32 value: {}", self.0);
}
}
fn main() {
let x = Struct(15_i32);
let _z = Struct(14.2_f64);
x.print();
//_z.print();//compile error
}
Playground
Alternatively you can use Borrow<S> trait as trick, you can restrict your generic parameter as like below : ( T: Borrow<S> means T can be borrowed as S ) .
impl<T> Printer for Struct<T>
where
T: Borrow<f64> + Debug,
{
fn print(&self) {
println!("Printing for f64 value: {:?}", self.0);
}
}
Playground
But since you can implement Borrow<f64> for any type, this kind of restriction may not be considered as strict.
Also just for the numeric primitives you can use traits from num-traits crate like ToPrimitive AsPrimitive
If you think about traits as compile time duck typing, then a better question would be: what are the exact traits you are looking for in a number? Most of the operations on them could be defined as trait constraints on your types, see: the standard operator traits.
Even if you would define a trait in an external crate and implement the behaviour for specific types only in that external crate, thinking that the trait implementation rules will help you there (i.e. a trait can only be implemented to a type if either the trait or the type or both are in your current crate) would still not limit anyone to implement your trait for their own types.
Therefore, I see no other option but to implement the behaviours without generics for each primitive number type. To avoid code duplication, I would probably use macros for this -- after all, if you think about it in some ways you would manually do what the compiler does while it monomorphises your generic code.
That being said I see no reason to limit behaviours to numbers but to certain traits and I would rely on them as I described it in the first paragraph.
This question already has answers here:
How do I implement a trait I don't own for a type I don't own?
(3 answers)
Closed 7 years ago.
So I see there are reasons to forbid orphan trait implementations because of forward compatibility considerations (to prevent the addition of a further trait implementation in a library from breaking somewhere where the type's trait is used) and it possibly making compilation a lot more difficult. But I wonder which workaround would be considered by the Rust community to be the most ideal one:
(Just in case this wasn't enough background: I am trying to use rusqlite with chrono's DateTime. So I want to implement rusqlite's FromSql and ToSql traits for DateTime<UTC> but that's apparently not as easy as I thought it'd be - I'm just starting out with Rust currently.)
Fork rusqlite and implement the trait. (I kind of feel like this is not the nicest way to do it because maybe it's just me who needs this trait implementation there and so I might end up having to keep my own fork up to date. Also I wasn't able to implement the traits because there are some complicated generics things that I don't understand perfectly yet.)
Implement my own DateTime struct (probably the best workaround but I feel like this is just some replication of work that shouldn't be nescessary).
Somehow "copy" the DateTime<UTC> trait and give it an alias and implement the FromSql and ToSql traits for my aliased type (however I think this is not trivial either and when I tried it I wasn't able to get it to work since it was still treated as an external type).
I hope somebody can explain to me how to best solve this issue, from my pure OOP experience I would just like to be able to inherit DateTime and implement the interface but (for valid reasons) this is not how it gets done in Rust...
The simplest way would be to use newtype pattern:
extern crate a;
extern crate b;
use a::SomeTrait;
use b::SomeStruct;
pub struct MySomeStruct(SomeStruct);
impl SomeTrait for MySomeStruct {
...
}
Here you create a wrapper around the foreign struct, and since this wrapper is a completely different type which belongs to your crate, you are free to implement a::SomeTrait for it. This is similar to your 2nd point, except that you absolutely don't need to reimplement the type from scratch.
Naturally, you won't be able to call all methods of SomeStruct on MySomeStruct. You must either forward all methods you want, or unwrap the inner value when you don't need its trait implementation anymore, or you can impl Deref for MySomeStruct { type Target = SomeStruct; ... }, but the latter is considered an antipattern.
I'm not sure what would be the most idiomatic, but it looks like the best approach would be to use the newtype pattern, which is a tuple-struct with one field. This creates a new type distinct from the old one, and you can implement the traits for that new type. To use the trait methods, you will need to wrap it in the newtype, but to use the normal methods, you'll use the normal struct without your newtype wrapper.
struct MyType(TheirType);
impl TheTrait for MyType {
....
}
fn main() {
let a = TheirType::new(....);
a.method_on_their_type();
let b = MyType(TheirType::new(....));
b.method_on_the_trait();
}