Background story: Traits are paramount in Rust. There's traits defined in crates, those you just derive and those you implement by hand. While using Rust I remarked that I needed a lot of time to copy/paste sample trait implementation from the docs, and thought that it would be great to have a place where you can have all the useful traits, and only the traits (not all the extra information you can find in the docs). Where you could for instance find your template implementation of the trait and just copy and paste it. In short, a place with cheatsheets about Rust traits. A few weeks ago I decided to make these cheatsheets by myself and created a static website. I thought that maybe it could be useful to others too, so here I am.
I've designed a static website with cheatsheets about Rust traits: https://traitzoo.gitlab.io/rust. I think it's better to see it by yourself, but if you want the details, for each (indexed) trait you have a single page with (what I thought to be) main takeaways:
A few lines to get the gist of it, before you potentially delve into the official docs
The list of trait requirements, with a link to other traits
The full definition, with required () and optional (•) items
And the implementation template, that you can copy + paste, plus some extra information blocks about whether it's an auto trait or can be derived
It's not meant to be exhaustive nor always precise (in particular about generics). I thought about it like a place for traits where you can explore them, discover some new ones (hopefully), compare and understand the differences between them, etc. There's the same for typeclasses by the way (https://traitzoo.gitlab.io/haskell) although it's far from filled.
I don't know what others mediums can be used to share it, if you have some I'm interested
Hope it can prove to be useful to others!
It would be better to use a programming-friendly, fixed-width font for the trait names on the front page instead of the current basic serif/Roman-style font.
It would be nice to apply some sort of grouping/sorting. A simple alphabetical ordering would be OK, logical/functional grouping would be even better. E.g., bring Send and Sync together.
Add and Mul are there, but not Sub and Div – this seems inconsistent. A couple more fundamental traits in the prelude are also missing (e.g. IntoIterator and Eq), even though these are way more likely to be implemented in ordinary code than arithmetic operations.
The description of Drop is weird. It says: "Can be dropped properly." But then are there types which can only be dropped improperly? I don't think that's a good way to put it. The actual meaning of Drop is "this type has a manually-defined custom destructor".
I'll definitely change the font for traits, and the description of Drop. These were my personal cheatsheets so there might be mistakes or imprecisions, in particular in the TL;DR section
About the fact some traits are lacking: I actually added them as I encountered them (and when I remembered to add them), but IntoIterator, Sub and the like all deserve to be there; there's no particular reason for them not to be included in it.
I'll think about how I can implement logical/functional grouping and that's a great idea, for now I'll just update to sort them in alphabetical order
The descriptive text for Applicative only has additional description beyond Functor that eludes to pure, but none that explains the existence of an operation like liftA2 (or <*>). (Note that liftA2 and <*> can be implemented in terms of each other (modulo usage of pureorfmap for one of the directions), but IMO liftA2 is conceptually simpler to explain.)
I will do that! You're right I forgot to mention it. I'm not really familiar with Applicative actually, I thought it was mainly about having a pure function
Since your unfamiliar, let me give the details for those equivalences.
(<*>) = liftA2 ($)
liftA2 f mx my = fmap f mx <*> my
-- or
liftA2 f mx my = pure f <*> mx <*> my
the pattern does continue, so you can do
liftA3 f a b c = fmap f a <*> b <*> c
liftA4 f a b c d = fmap f a <*> b <*> c <*> d
etc...
With infix fmap, i. e. <$>, this is commonly written f <$> a <*> b <*> c, and so on. It's a fun exercise to look at the type signatures to verify/understand
why this arbitrary-arty liftA…-pattern works
how <*> and liftA2 would be implemented for monads using "bind" (>>=) or do notation.
By the way liftA… functions are a generalization of the older liftM… functions.
An interesting first example of an implementation of Applicative that isn't a Monad is ZipList. Practical use cases are in parser combinators, some of which can be more performant interface when you use an Applicative API instead of a monadic one, and some might want to offer static analysis thats only possible without the full flexibility of a Monad interface.
So it's sort of a way to use f a on "multi-arguments"/curried functions (a ->b -> c, a -> b -> c -> d, etc.)? Or a way to lift function too to the functor space, as I read (and so for instance to use it for curried functions)
So it would be nice to keep the definition form instead of only showing the methods and associated types.
It's also important to know the trait bounds on type parameters (like T: ?Sized here).
And it's clear for me to understand a trait from a concrete example: code from the std library is super neat, so a templete like the following tells much.
// A good example
impl AsRef<[u8]> for str {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
Thanks for spotting the missing type in AsRef. About keeping the definition as a whole, it's a choice I made to focus only on the methods in the definition, and as I said I did not want to clutter too much with generics, but point taken. About the trait bounds, they are in the trait requirements lists, except for the Sized trait you mentioned. It's currently not in there because it would currently break links in this section, but it would normally be there too. There's of course a lot of ways this could be improved, but as of now it was sort of a first draft and a draft that served me relatively well in my use of Rust.
I don't think I've mentioned it before, but naturally if you want to add PRs to it you're welcome (for instance if you want to add traits or have ideas of sections)
Forgot to talk about the std library and concrete examples. I understand your point about giving concrete examples. I actually started like this but thought it would be better to have uniform examples across traits so I used structures names that were less meaningful in context. The implementation section was thought more to be a copy/paste area. About the std, I find it really great, and it would be nonsense to try to mimicry it. But I thought that having fewer information in one place could be better, in particular about the examples you mention that sometimes find hard to find in the docs. To give you details, he choice I made was not to fill up the body of the traits methods if there was nothing particular for this trait in the way it can be implemented. Examples of the contrary are Displays, Debug, etc. where you often have the same kind of thing inside the body of your trait method and it's often very specific (having a write!(f,..) or a f.debug_struct("Point").field(...).finish(). For others, I try to keep it to a minimal, and not too much thing in it, and have approximately the same struct names between traits. But I agree your example is more insightful, so I might use concrete examples in the future, as long as there are not too cluttered.
As suggested by @vague I've added ?Sized traits bounds (and more generally, optional and negative trait bounds/requirements can be listed, which was not possible before)
Hello,
It's been a while, but @H2CO3's wish has been granted: traits are now grouped by similar topics which makes things much more readable
I've been adding some new Rust traits, but also some Haskell typeclasses! And now there are links to the official docs within the Rust cheatsheets to have the complete explanation
Feel free to take a look and let me know if you have any comments, suggestions or found typos