1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//! Just like something else
//!
//!   - **Date:** 2015-12-27
//!   - **Subject:** Generics, traits, and shared behavior in Rust.
//!   - [**Audio**][mp3]
//!
//! [mp3]: https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e008.mp3
//!
//! <audio style="width: 100%" title="Just like something else" controls preload=metadata src="https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e008.mp3">
//!
//! Notes
//! -----
//! In this episode we cover---at a *very* high level---two more fundamental
//! concepts in Rust programming: generics and traits.
//!
//! Generics gives us the ability to write types and functions which can be
//! used with more than one type. Traits give us the ability to specify behavior
//! which can be implemented for more than one type. The combination gives us
//! powerful tools for higher-level programming constructs in Rust.
//!
//! ### Comments on source code
//!
//! Now that we have a handle on [how tests work][e007], we'll use them to
//! validate the behavior of our code going forward. This is great: we can show
//! that the tests do what we think.
//!
//! To today's point, though: we actually know even apart from whether the tests
//! *run* successfully that these generic functions and the associated traits
//! are behaving as we want. Failure with generics is a *compile*-time error,
//! not a runtime error.
//!
//! [e007]: https://www.newrustacean.com/show_notes/e007/
//!
//!
//! Links
//! -----
//!
//!   - Rust Book
//!       + [Generics][l1]
//!       + [Traits][l2] -- includes a discussion of *trait bounds* and *generic
//!         *traits*
//!   - Rust by Example
//!       + [Generics][l3]
//!       + [Traits][l4]
//!       + [Generic *traits*][l5]
//!       + [Traits *bounds*][l6]
//!   - [Generics and traits in use in Diesel][l7]
//!
//! [l1]: https://doc.rust-lang.org/book/generics.html
//! [l2]: https://doc.rust-lang.org/book/traits.html
//! [l3]: http://rustbyexample.com/generics.html
//! [l4]: http://rustbyexample.com/trait.html
//! [l5]: http://rustbyexample.com/generics/gen_trait.html
//! [l6]: http://rustbyexample.com/generics/bounds.html
//! [l7]: https://github.com/sgrif/diesel/blob/master/diesel/src/types/mod.rs
//!
//!
//! Sponsors
//! --------
//!
//!   - Chris Palmer
//!   - [Derek Morr][sponsors-2]
//!   - Luca Schmid
//!   - Micael Bergeron
//!   - Ralph Giles ("rillian")
//!   - reddraggone9
//!   - [William Roe][sponsors-7]
//!
//! [sponsors-2]: https://twitter.com/derekmorr
//! [sponsors-7]: http://willroe.me
//!
//! ### Become a sponsor
//!
//!   - <a href="https://www.patreon.com/newrustacean" rel="payment">Patreon</a>
//!   - [Venmo](https://venmo.com/chriskrycho)
//!   - [Dwolla](https://www.dwolla.com/hub/chriskrycho)
//!   - [Cash.me](https://cash.me/$chriskrycho)
//!
//!
//! Follow
//! ------
//!
//!   - New Rustacean:
//!     + Twitter: [@newrustacean](https://www.twitter.com/newrustacean)
//!       + App.net: [@newrustacean](https://alpha.app.net/newrustacean)
//!     + Email: [hello@newrustacean.com](mailto:hello@newrustacean.com)
//!   - Chris Krycho
//!     + Twitter: [@chriskrycho](https://www.twitter.com/chriskrycho)
//!       + App.net: [@chriskrycho](https://alpha.app.net/chriskrycho)

use std::fmt;

/// Demonstrate a function *generic* over any type.
///
/// This uses a cross-language convention for generics, where `T` represents the
/// generic *type*. If we have more than one generic type, it's traditional to
/// represent it with following letters, after `T`: `U`, `V`, `W`, etc. (If you
/// have four *different* generic parameters, I'm probably going to look askance
/// at your API design, though, to be honest.)
pub fn a_generic<T>(_t: T) {
    println!("The function works, but I can't actually do anything with the `_t`.");
    println!("Why? Well, because it might not have the `Display` or `Debug` traits implemented.");
    println!("What's a trait? I'm so glad you asked.");
}

/// Demonstrate a function with a *trait bound on a generic*.
pub fn a_generic_printable<T: fmt::Debug>(t: T) {
    println!("This function can actually debug-print `t`, whatever it may be.");
    println!("So: {:?}", t);
}

/// This is `Option<T>`, but using Haskell's names instead.
pub enum Maybe<T> {
    Nothing,
    Just(T),
}

/// A simple type to illustrate trait implementation.
pub struct SimpleType {
    a: String,
    b: i32,
}

/// Define the display format for the `SimpleType`.
///
/// Note that this works because `String` and `i32` both already have display
/// types implemented themselves!
impl fmt::Display for SimpleType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "string: {} | integer: {}", self.a, self.b)
    }
}

/// This is just a container which can hold any two types.
///
/// These types can even be the same, but they don't have to be. Moreover, they
/// can be generic types themselves; as you can see in the tests below, you can
/// use built-in or user-created generic types within this generic type.
pub struct GenericContainer<T, U> {
    pub t: T,
    pub u: U,
}

/// Show that the generics work!
#[cfg(test)]
mod tests {
    use super::*;

    /// An example struct for the tests.
    #[derive(Debug)]
    struct TestPoint {
        x: f32,
        y: i32,
    }

    /// An example enum for the tests.
    #[derive(Debug)]
    enum TestEnum {
        Nope,
        SomePointTuple(f32, i32),
        /// Any tuple type
        SomeAnonStruct {
            x: f32,
            y: i32,
        },
        /// Functionally just like `TestPoint`
        SomePointStruct(TestPoint), // Embed an actual `TestPoint`
    }

    /// All of these tests will pass.
    #[test]
    fn test_generic_fn() {
        a_generic(1);
        a_generic(());
        a_generic((1, 2));
        a_generic(TestPoint { x: 14.0, y: 12 });
        a_generic(TestEnum::Nope);
        a_generic(TestEnum::SomePointTuple(13.0, 10));
        a_generic(TestEnum::SomeAnonStruct { x: 24.3, y: 10 });
        a_generic(TestEnum::SomePointStruct(TestPoint { x: 1.2, y: 3 }));
    }

    /// So will all of these.
    #[test]
    fn test_generic_fn_with_debug_print() {
        a_generic_printable(1);
        a_generic_printable(());
        a_generic_printable((1, 2));
        a_generic_printable(TestPoint { x: 14.0, y: 12 });
        a_generic_printable(TestEnum::Nope);
        a_generic_printable(TestEnum::SomePointTuple(13.0, 10));
        a_generic_printable(TestEnum::SomeAnonStruct { x: 24.3, y: 10 });
        a_generic_printable(TestEnum::SomePointStruct(TestPoint { x: 1.2, y: 3 }));
    }

    #[test]
    fn test_generic_enum() {
        // `_nothing` must have its type specified because it can't be inferred
        // from the context. Generics can be type-inferred (see below), but as
        // with all types in Rust, when they can't be, you specify them.
        let _nothing: Maybe<i32> = Maybe::Nothing;
        let _just_25 = Maybe::Just(25);
        let _just_str = Maybe::Just("whoa");
        let _just_slice = Maybe::Just([1, 2, 3]);
        // Here we have a generic enum, wrapping a generic container, `Vec<T>`!
        let _just_vec = Maybe::Just(vec![1, 2, 3]);
        // Things could get complicated if we need to define a `Maybe::Nothing`
        // for a `Vec`: we need to specify the `Vec` type as well:
        let _no_vec: Maybe<Vec<i32>> = Maybe::Nothing;
        // Normally that woudn't be a problem, because it would be inferred by
        // the context, with a pattern match:
        let pattern = false;
        let _maybe_vec = match pattern {
            false => Maybe::Nothing,
            true => Maybe::Just(vec![1, 2, 3]),
        };
    }

    #[test]
    fn test_generic_struct() {
        // The generic container can contain "normal" (non-generic) types.
        let _container = GenericContainer {
            t: 14.0,
            u: "alpha",
        };
        // But it can also contain generic types, like `Vec<T>` or the `Maybe`
        // type we defined above.
        let _another = GenericContainer {
            t: vec![1, 2, 3],
            u: Maybe::Just("a string"),
        };
    }

    #[test]
    fn test_impl_display() {
        let simple = SimpleType {
            a: "some string".to_string(),
            b: 4096,
        };
        println!("simple is {}", simple);
    }
}