4 ms·
Can you give me an example of a function, enum or struct that is generic without traits?
by rkangel 9y ago
Can you give me an example of a function, enum or struct that is generic without traits?
- icen 9y agoSomewhat facetiously: fn identity<T>(t: T) -> T { t } Has no trait bounds, and is clearly generic. You typically can't do very much with completely free type variables, but Rust has syntactic support for them.
- Nullabillity 9y agoAnd even that implicitly relies on the Sized trait.
- kibwen 9y agoThe standard library's own `Vec` type is an example of a struct that is generic without traits. See the source: https://github.com/rust-lang/rust/blob/4ed2edaafe82fb8d44e81e00ca3e4f7659855ba2/src/libcollections/vec.rs#L299 https://github.com/rust-lang/rust/blob/4ed2edaafe82fb8d44e81... . In fact, almost no struct or enum uses traits in combination with generics. On the other hand, generic functions do almost always leverage traits, because otherwise you basically can't do anything in the function with the generic parameter. However, note that there does exist a very important generic function in the stdlib that doesn't use traits at all: `std::mem::drop`. Here's the source, which is very, very interesting: https://github.com/rust-lang/rust/blob/4ed2edaafe82fb8d44e81e00ca3e4f7659855ba2/src/libcore/mem.rs#L666 https://github.com/rust-lang/rust/blob/4ed2edaafe82fb8d44e81... . And no, I'm not being facetious when I call it interesting; figuring out what `std::mem::drop`'s purpose is from its amusing implementation is a test that you understand what ownership means in Rust. :)
- rkangel 9y agoThat's the way round I meant. Yes you can have generics without traits (particularly with data structures as you've pointed out). Not sure of anything that uses traits without generics.
- kibwen 9y ago> Not sure of anything that uses traits without generics. Traits do a lot of things in Rust that have nothing to do with generics. :) Implementing a trait is how one gives a type a destructor. Implementing various traits (the ones in std::ops) allows one to do operator overloading for user-defined types. Defining a trait allows one to give methods to types that are defined in other compilation units, including the standard library, e.g.: trait Foo { fn foo(self); } impl Foo for i32 { fn foo(self) { println!("Hello, traits!"); } } fn main() { 42.foo(); // Hello, traits! }
- rkangel 9y agoThank you for that.
- saghm 9y agoHow about Read and Write, two of the most widely-used traits? https://doc.rust-lang.org/std/io/trait.Read.html https://doc.rust-lang.org/std/io/trait.Read.html https://doc.rust-lang.org/std/io/trait.Write.html https://doc.rust-lang.org/std/io/trait.Write.html
- rkangel 9y agoBut those are excellent examples of the use of generics. They allow you write code that can operates on a generic object, not know what type it is, but know that you can read from it.
- saghm 9y agoOh, I think I see what you're saying. If I'm understanding correctly, then you're saying that the types that traits define are only used with generics? This isn't quite correct, as you can use trait objects to get dynamic dispatch rather than using generics. But yes, in general, functions that are defined to take traits as parameters generally use generics. I'm not sure I'd still consider the idea of traits to be inherently tied to generics, though; the Iterator trait, for instance, is usually just used to call Iterator methods on different types rather than as a way to bound the types of function parameters.