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
243
244
245
246
//! Functionalized
//!
//!   - **Date:** October 29, 2015
//!   - **Subject:** Functions, methods, closures, and function as arguments!
//!   - [**Audio**][mp3]
//!
//! [mp3]: https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e004.mp3
//!
//! <audio style="width: 100%" title="Functionalized" controls preload=metadata src="https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e004.mp3" />
//!
//! # Notes
//!
//! This week's episode covers the basics of all sorts of functions: normal
//! functions, methods, and closures.
//!
//! ## Closures
//!   - [An explanation (in Ruby) by Martin Fowler][notes-1]
//!   - [Rust book][notes-2]
//!   - [Rust by Example][notes-3]
//!   - ["What is a closure?" (Progammers Stack Exchange)][notes-4] -- the first
//!     answer is the best, but the second answer may be a helpful stepping
//!     stone for people just getting their heads around this and coming from
//!     OOP languages like C++ or Java (even though I disagree with the
//!     explanation in some ways).
//!   - ["What is a closure?" (Stack Overflow)][notes-5] -- careful, thorough
//!     answer using JavaScript as an example.
//!
//! [notes-1]: http://martinfowler.com/bliki/Lambda.html
//! [notes-2]: https://doc.rust-lang.org/book/closures.html
//! [notes-3]: http://rustbyexample.com/fn/closures.html
//! [notes-4]: http://programmers.stackexchange.com/questions/40454/what-is-a-closure
//! [notes-5]: http://stackoverflow.com/questions/36636/what-is-a-closure
//!
//! # Links
//!
//!  - [Exercism][link-1] (hat tip: [Lechindanier on GitHub][link-2])
//!  - [Rust Learning][link-3]
//!  - [Rust and Swift (viii)][link-4]
//!
//! [link-1]: http://exercism.io/languages/rust
//! [link-2]: https://github.com/Lechindianer
//! [link-3]: https://github.com/ctjhoa/rust-learning
//! [link-4]: http://www.chriskrycho.com/2015/rust-and-swift-viii.html
//!
//! # Follow/Support
//!
//!   - New Rustacean:
//!     + Twitter: [@newrustacean](https://www.twitter.com/newrustacean)
//!       + App.net: [@newrustacean](https://alpha.app.net/newrustacean)
//!       + <a href="https://www.patreon.com/newrustacean" rel="payment">Patreon</a>
//!       + [Dwolla](https://www.dwolla.com/hub/chriskrycho)
//!     + Email: [[email protected]](mailto:[email protected])
//!   - Chris Krycho
//!     + Twitter: [@chriskrycho](https://www.twitter.com/chriskrycho)
//!       + App.net: [@chriskrycho](https://alpha.app.net/chriskrycho)

/// Create a module so we can see public/private behavior.
///
/// We will discuss modules in more detail in the future.
mod struct_container {
    /// Shows how methods work. Elaborates only a little on the e001 examples.
    pub struct MethodDemonstrator {
        // Public data.
        pub an_int: i64,
        pub a_string: String,

        // Private data.
        /// A tuple holding a floating point value and a string slice. (We'll
        /// discuss string slices in a future episode.)
        a_tuple: (f64, String),
    }

    impl MethodDemonstrator {
        /// A standard constructor pattern.
        ///
        /// You've seen this before, in the e001 code!
        ///
        /// Note that Rust doesn't have constructors in the same sense as C++
        /// or Java: you can construct a `MethodDemonstrator` just as this
        /// function does somewhere else. Using `new` is a convenient
        /// convention, so you can just call `MethodDemonstrator::new()` to get
        /// an instance, rather than needing to worry about the details of the
        /// struct.
        ///
        /// This is particularly important because not all types are
        /// necessarily public; you may not be able to construct a given
        /// `struct` *correctly* if it has hidden types, especially computed
        /// properties, which should be initialized during its construction.
        pub fn new() -> MethodDemonstrator {
            MethodDemonstrator {
                an_int: 0,
                a_string: "Nothin' into nothing, divide the nothin'...".to_string(),
                a_tuple: (2.0, "Twice 1.0".to_string()),
            }
        }

        /// A standard struct instance method.
        ///
        /// Note that *instance* methods take a reference to `self` as the
        /// first argument. It *needs* to be a reference for normal methods,
        /// because if it isn't, the struct instance will be moved into the
        /// function---the method will own, not just borrow---the reference,
        /// and after the method call ends, the item will be destroyed.
        ///
        /// Of course, if you need to write a custom destructor for a more
        /// complex type, you now have a pretty good idea how to write the first
        /// argument to that method...
        pub fn method(&self) {
            println!(
                "The values of the object are: {:}, {:}, {:}, {:}",
                self.an_int, self.a_string, self.a_tuple.0, self.a_tuple.1
            );
        }

        /// A getter for data which is not publicly accessible in the type.
        ///
        /// If you try to access the tuple contents directly, e.g. with an
        /// instance of the struct *outside this module*, you will fail. (See
        /// the example in `demonstrate_methods`.)
        ///
        /// The data can be accessed by the struct itself, however, so you can
        /// get or set the data, as here.
        ///
        /// We use `clone` because we need to get not the items themselves
        /// (which we could otherwise only get as references) but their values;
        /// the `clone` method is from the `Clone` trait, which is available on
        /// many basic types in the system. Again, we will return to `trait`s in
        /// a later episode.
        pub fn get_hidden_data(&self) -> (f64, String) {
            self.a_tuple.clone()
        }
    }
}

/// Shows how to use both struct and instance methods.
///
/// Note that struct methods are called with the `::` syntax, which is the same
/// as the module syntax! We'll come back to this soon. Note as well that the
/// `.` syntax used for instance methods corresponds to the use of `self` (in
/// whatever form) in
pub fn demonstrate_methods() {
    // Just builds a struct instance as expected.
    let a_struct = struct_container::MethodDemonstrator::new();

    // Call a basic method using `.` notation (which supplies `self` as the
    // first argument, in the appropriate fashion for the method).
    a_struct.method();

    // This won't work: the `a_tuple` member is private.
    //
    //     println!("{:?}", a_struct.a_tuple);
    //
    // However, we can get at the data if the struct gives us access:
    println!("{:?}", a_struct.get_hidden_data());
}

/// Shows how to take a function as an argument.
///
/// Note that this involves specifying a *generic* (the `<F>` syntax), bounded
/// by a `trait` (the `where...` syntax), a concept to which we will return in
/// much more detail in a few episodes.
pub fn apply_function_to_i64<F>(a_number_function: F, the_number: i64) -> i64
where
    F: Fn(i64) -> i64,
{
    let result = a_number_function(the_number);
    println!("{:?}", result);
    result
}

/// Show how to call a function with a function as an argument.
///
/// Both normal functions and closures can be passed as arguments to functions
/// which accept functions as arguments, as long as their type definition
/// matches the requirements of the destination function.
pub fn demonstrate_function_arguments() {
    /// Implements the signature required for `apply_function_to_i64`.
    ///
    /// Note that this is a nested function definition! It is unavailable
    /// outside the `demonstrate_function_arguments` body.
    fn double(n: i64) -> i64 {
        n * 2
    }

    // You can pass a normally defined function.
    assert_eq!(apply_function_to_i64(double, 2), 4);

    // You can also pass a closure, defined inline or standalone.
    // Inline closure definition:
    assert_eq!(apply_function_to_i64(|n| n * n, 5), 25);

    // Standalone closure definition
    let cube = |n| n * n * n;
    assert_eq!(apply_function_to_i64(cube, 9), 729);

    // You cannot use a function which does not meet the definition of the
    // target function, however, so this won't compile:
}

/// Shows how closures can act on elements within their environment.
///
/// Closures are handy for more than merely a quick and easy way to write a
/// callback; they also serve as one possible way to hide information or
/// implementation details. While that's not as strictly necessary in Rust as it
/// is in e.g. JavaScript, it still has a great deal of utility, especially in
/// more functional programming styles.
pub fn demonstrate_closure_environment() {
    /// Returns a closure which has access to the internal contents of this
    /// function even after it goes out of scope.
    fn get_a_closure() -> Box<Fn(f64) -> f64> {
        let x = 14.0;

        // Now we define a closure. I'll explain the bits with `move` and
        // `Box::new` here next week; for now, suffice it to say that they're
        // necessary for Rust's memory guarantees and scoping behavior.
        let do_with_captured_x = move |n| n * x;
        Box::new(do_with_captured_x)
    }

    // Now call the closure. Note that even though we're now in a scope where
    // the value of `x` defined doesn't exist (try `println!("{:}", x);` if you
    // want to verify this), the closure still has access to it.
    let the_closure = get_a_closure();
    assert_eq!(the_closure(2.0), 28.0);

    /// Calls whatever function you hand it with the value 14.0
    fn takes_a_closure_with_14<F>(f: F) -> f64
    where
        F: Fn(f64) -> f64,
    {
        f(14.0)
    }

    // Note that the closure can interact with *this* environment as well as the
    // items handed to it by the function which calls it, because the `y` term
    // is available in its surrounding scope.
    let y = 3.0;
    assert_eq!(takes_a_closure_with_14(|n| n * y), 42.0);
}

#[test]
fn demonstrate() {
    demonstrate_function_arguments();
    demonstrate_methods();
    demonstrate_closure_environment();
}