Returning Values

A method returns the value of its last expression, so there’s no need to explicitly return that or declare its type. However, if you want to document or directly control that return type, you can explicitly specify the type, as in this example:

 def​ ​typed_method​ : Array(Int32)
  (42..47).​to_a​.​select​ { |n| n % 4 == 0 }
 end
 
 typed_method ​# => [44]

You can also explicitly use Nil as your return type if you want to indicate that this is a so-called side-effect method: only important for what it does, not for what it returns. Developers consuming your method will need to be prepared for that, but at least it shouldn’t be a surprise nil.

If you need to return multiple values, you can pack them together in a tuple or an array. Unpack the values by using destructuring (see Unpack the values by using Your Turn 4):

 # Multiple return values
 def​ ​triple_and_array​(s)
  {s * 3, s.​split​}
 end
 
 # unpacking:
 ret = triple_and_array(​"42"​) ​# => {"424242", ["42"]}
 ret[0] ​# => "424242"
 ret[1] ​# => ["42"]
 # or:
 num, arr = triple_and_array(​"gold"​)
 num ​# => "goldgoldgold"
 arr ​# => ["gold"]

Using the Splat Argument *

If you want your method to accept a variable number of parameters, then you can’t give a name to each of your arguments. Instead, use one argument prefixed with a *, to create a so-called splat argument. The method can then take from 0 to an unlimited number of parameters because they’re all converted into one tuple.

Say, for example, you want to calculate the salaries for an unknown number of employees:

 def​ ​salaries​(*employees)
  employees.​each​ ​do​ |emp|
 # calculate salary
  puts ​"​​#{​emp​}​​'s salary is: 2500"
 end
 end
 
 salaries() ​# =>
 salaries(​"Jones"​) ​# => Jones's salary is: 2500
 salaries(​"Baudelaire"​, ​"Rogers"​, ​"Gandhi"​)
 
 # =>
 # Baudelaire's salary is: 2500
 # Rogers's salary is: 2500
 # Gandhi's salary is: 2500

Using the splat argument doesn’t mean you have to sort out all of the arguments yourself. Crystal offers a different approach, using just a bare * to indicate that all arguments after the * must be named with labels. That approach works like this:

 def​ ​display​(n, *, height, width)
 "The shape has height ​​#{​height​}​​ and width ​​#{​width​}​​"
 end
 
 display 3, ​height: ​2, ​width: ​5
 # => "The shape has height 2 and width 5"

You can even give a named parameter another name to use in the method’s body so that your code reads more naturally:

 def​ ​increment​(number, by value)
  number + value
 end
 
 p increment(10, ​by: ​10) ​# => 20

Another classic situation is the pesky problem of creating a string of values delimited by a certain character—but that character can’t appear after the last value. For example, we want “1-2-3” but not “1-2-3-“. This solution takes a variable number of values args, denoting the delimiter as with joinerjoiner is the internal name used inside the method, and with is the name used when calling the method to pass the parameter’s value:

 def​ ​join​(*args, with joiner)
  String.​build​ ​do​ |str|
  args.​each_with_index​ ​do​ |arg, index|
  str << joiner ​if​ index > 0
  str << arg
 end
 end
 end
 
 join 1, 2, 3, ​with: ​​"-"​ ​# => "1-2-3"
 join 1, 2, 3, 4, 5, ​with: ​​"*"​ ​# => "1*2*3*4*5"

Your Turn 1

a. Total: Write a method total to calculate the sum of an arbitrary amount of numbers. Change total so that the sum starts from an initial value.

b. Splat a Tuple:

You can also unpack a tuple (which we explored in Your Turn 4) directly into the arguments of a method. Suppose you want to do this:

 def​ ​add​(n, m)
  n + m
 end
 
 tpl = {42, 108}
 add tpl

Does this work? Can you explain this?

You have to call it like this: add *tpl, which is called splatting a tuple. If tpl is a named tuple and you want to use the argument names, you have to use a double splat **. Try that out.

Another trick[31] uses **argument to capture a variable number of named parameters into a named tuple.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.12.140