I've come across a case where I have a generic that needs to satisfy two traits.
pub struct FileReader<R: Read + Seek> { /* private fields */ }
These are standard traits and I can find their implementors individually. Then I can see which implementors are common and use one of them.
However this made me consider if there's a way to query - cargo docs, the compiler or something to find possible structs that implement a given set of traits. This might be useful when generics have many trait conditions and/or a trait has many implementors.
Cargo docs already has a search bar for queries but it's for searching with names or with function types. Not one level up queries like these.
Related
Is there a way to get the Rust compiler to add derives on all structs, possibly with some kind of matching, like only structs in X crate, or maybe recursively apply #derives? I would rather not vendor those crates because it'd be a lot of work to keep them up to date.
No, the Rust compiler does not provide such a facility.
You can't derive traits for types outside of your own crate. So you have two options:
Submit a PR to the crate in question, to add the implementations. Many projects will accept changes that implement common traits like serde::Serialize etc, provided they are feature-gated
Use wrapper types and implement the traits there. e.g. if the type in question is Uuid from the uuid crate:
pub struct MyUuid(uuid::Uuid);
impl MyTrait for MyUuid {
// etc
}
Note that you can't derive traits that need to know the fields of third party types because the tokens will not be available.
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.
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.
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.
Rust's enums are algebraic datatypes. As far as I can tell this seems to subsume what struct is. What is different about struct that necessitates keeping it?
First of all, you are correct that semantically enum is strictly superior to the struct as to what it can represent, and therefore struct is somewhat redundant.
However, there are other elements at play here.
ease of use: the values within an enum can only be accessed (directly) through matching; contrast with the ease of use of accessing a struct field. You could write accessors for each and every field, but that is really cumbersome.
distinction: an enum is a tagged union, a struct has a fixed-layout; we (programmers) generally like to put labels on things, and therefore giving different names to different functionality can be appreciated.
As I see it, struct is therefore syntactic sugar. I usually prefer lean and mean, but a bit of sugar can go a long way in increasing what can be represented tersely.
Firstly, Rust has a wide array of data types:
Structs with named fields (struct Foo {bar: uint})
Tuple structs (struct Foo(pub Bar, Baz))
Structs with no fields (struct Foo;)
Enums, with various types of variants:
Variants with no fields (eg None)
Tuple variants (eg Some(T))
Struct variants (eg Some { pub inner :T })
This gives the programmer some flexibility in defining datatypes. Often, you don't want named fields, especially if the struct/variant has only one field. Rust lets you use tuple structs/tuple variants in that case.
If structs were removed from Rust there would be no loss of functionality, enums with struct variants could be used again. But there would be an overwhelming number of single-variant enums which would be unnecessary and cumbersome to use.
Not 100% correct, but another nice way to think about it : enum isn't actually superior to struct, the syntax sugar just makes it look like it is.
An enum is a sum type meaning that it's value is one value of one of a set of other types. The Result<T, E> type is either of type T or E. So each enum variant has exactly one type associated with it. Everything else (no type, tuple variants and struct variants) could be syntax sugar.
enum Animal {
// without syntax sugar
Cat(i32),
// desugars to `Dog(())` (empty tuple/unit)
Dog,
// desugars to `Horse((i32, bool))` (tuple)
Horse(i32, bool),
// desugars to `Eagle(GeneratedEagleType)` and a struct definition outside
// of this enum `struct GeneratedEagleType { weight: i32, male: bool }`
Eagle { weight: i32, male: bool }
}
So it would be enough if each enum variant would be associated with exactly one type. And in that case enum is not superior to struct, because it cannot construct product types (like struct).
To be able write the "type definition" inside the enum variant definition is just for convenience.
Also: struct is superior to "tuple structs" and "tuples", too. If we ignore the names those three things are nearly equivalent. But Rust still has those three different kinds of types for convenience.
Please note that I don't know if those enum definitions are actually syntax sugar or not. But they could be and that might help think about. it
Visibility
Not to find reason in what may be a transient implementation detail (I'm not on the core team and have no insight), but
A public enum can not hold or contain a private struct.
A public struct can hold or contain a private enum.
See also
Why does "can't leak private type" only apply to structs and not enums?
You are right that enums and traits and their inheritance by structs both implement algebraic datatypes.
However traits is an extensible set of types, where any stuct can be attributed any trait from any piece of code. Using introspection, it is possible to expect a value with a given trait, and dynamically dig out the actual type of a struct. But that type is among a set of types that is unpredictable, because any struct could be given the said trait from anywhere.
Whereas enums define once and for all a limited type hierarchy, making it predictable and straightforward to go match subtypes as if they were simple values. The language features surrounding enums can therefore be optimized so that the type checks occur statically, providing much greater performance, and some sugar in the language. But also the hierarchy description is contained to the enum definition, and does not impact the trait type system.
TL;DR: enum narrows down a hierarchy of types in a contained manner, instead of relying on traits that are extensible by any piece of code and impacts everything.
Another important distinction along with the above answers is that enum at one point can ONLY be one of the values stated while struct represents values for all the parameters for that instance.
eg.
enum Things{
Box,
Page(i32),
}
struct Things{
box: Option<String>,
page: i32,
}
In the above case a single enum can either be a Box or a Page, while a single instance of struct will represent a box and a page.