Any method defined by a class in Ruby can accept a process object (Proc) as an additional parameter, in a method, you only need to use the yield expression to call this process object. During the call, the parameter of the object is specified by the yield expression, and its return value is returned as the value of the yield expression.
The following is an example in the ruby document.
Def threetimes <br/> yield <br/> end <br/> threetimes {puts "hello"} <br/> # output result <br/> Hello <br/>
The global method threetimes defined in the preceding example uses the Yield Expression statement three times to call the accepted process object. The function of actually calling the process object is to print hello, therefore, the result is to print three rows of hello.
In the above example, it is not difficult to conclude that the process object of the method in ruby is essentially equivalent to the callback function (callback), and its function is equivalent to the listener of Java and the delegate of. net. Because Ruby has the characteristics of Dynamic Language, the parameter and return value types of the Process object do not need to be defined in advance like listener and delegate. Therefore, this callback can be called a generic callback ). The process body in Ruby can be stored in variables, which are usually inactive and executed only when called. Therefore, it has the characteristics of lazy function.
Note that the functions implemented by the yield keyword in ruby are different from those of the same name in Python and C #. The latter two Save the function field before returning their own parameters to the caller for future calls. This type of feature is generally called coroutine ).
Try to compare the following Python Code
Def F (): <br/> yield "hello" <br/> G = f () <br/> G. next (); G. next (); G. next () <br/> # output result <br/> 'hello' <br/>
The following is a complex example (taken from the ruby document), and uses C ++ to simulate its functions.
Ruby code
Class array <br/> def inject (n) <br/> Each {| value | n = yield (n, value )} <br/> n <br/> end <br/> def sum <br/> inject (0) {| n, value | n + value} <br/> end <br/> def product <br/> inject (1) {| n, value | N * value} <br/> end <br/> def find <br/> for I in 0... size <br/> value = self [I] <br/> return value if yield (value) <br/> end <br/> return nil <br/> end <br/> [1, 2, 3, 4, 5]. sum #15 <br/> [1, 2, 3, 4, 5]. product #120 <br/> [1, 2, 3, 4, 5]. find {| v | V * V> 10 }# 4 <br/>
C ++ code
# Include <iostream> <br/> # include <boost/foreach. HPP> <br/> # include <boost/assign. HPP> <br/> # include <boost/function. HPP> <br/> # include <boost/spirit/Phoenix. HPP> <br/> using namespace STD; <br/> using namespace boost; <br/> using namespace assign; <br/> using namespace Phoenix; </P> <p> template <typename T> <br/> struct array <br/> {<br/> typedef vector <t> self_t; <br/> typedef boost: function <T (t, t)> func_t1; <br/> typedef boost: function <bool (t)> func_t2; </P> <p> array (const self_t & ARR): m_arr (ARR) {}</P> <p> T inject (t n, func_t1 F) {<br/> boost_foreach (t v, m_arr) <br/> N = f (n, V); <br/> return N; <br/>}< br/> T sum () {<br/> return inject (0, arg1 + arg2 ); <br/>}< br/> T product () {<br/> return inject (1, arg1 * arg2 ); <br/>}< br/> const T * Find (func_t2 f) {<br/> boost_foreach (t v, m_arr) <br/> If (f (v )) <br/> return & V; <br/> throw NULL; <br/>}< br/> PRIVATE: <br/> const self_t & m_arr; <br/>}; </P> <p> int main () <br/>{< br/> vector <int> V; <br/> V + = 1, 2, 4, 5; <br/> array <int> A (V); <br/> cout <. sum () <Endl; <br/> cout <. product () <Endl; <br/> cout <*. find (arg1 * arg1> 10) <Endl; </P> <p> return 0; <br/>}< br/> // 15 <br/> // 120 <br/> // 4
Ruby Code Description
- The array class is Ruby's built-in array type. Similar to the list type of Python, its member type is unrestricted.
- The each method of the array class traverses all array members, and uses the array members as parameters to call their callback functions in sequence.
- The inject method of the array class is the auxiliary method of the sum method and the product method, and the parameter n is accepted as the initial value. This method first calls the each method to traverse all array members, call the callback function using the array member value and its own parameter n as the parameter, and save the returned values of each call in Variable N. Finally, return the value of Variable N.
- The sum method of the array class calls the inject method to implement the summation function. The initial value of the inject method is 0, and the callback function is used to return the sum of the value of the array member and parameter n.
- The product method of the array class calls the inject method to implement the product function. The initial value of the inject method is 1, and the callback function is the product of the returned array member value and parameter n.
- The find method of the array class traverses all array members, and uses the array members as parameters to call the callback function in sequence to check the value of the callback function. If the return value is true, the traversal is aborted, this member is returned. If true is returned for one call, the Null Object NIL is returned.
C ++ Code Description
- The ruby array is simulated using the vector component of the standard library.
- The ruby array traversal is simulated using the foreach component of the boost library.
- The ruby callback function is simulated using the function component of the boost library.
- The assign component of the boost library is used to simulate Ruby array initialization.
- The lazy functions of Ruby callback functions are simulated using the boost library's Phoenix sub-library. The Lambda sub-library of the boost library can also complete this function, but the Phoenix sub-library of the spirit sub-library is more powerful, and its functional programming function far exceeds the lambda sub-library, which is recommended.