What does a double * (splat) operator do
Ruby 2.0 introduced keyword arguments, and **
acts like *
, but for keyword arguments. It returns a Hash with key / value pairs.
For this code:
def foo(a, *b, **c)
[a, b, c]
end
Here's a demo:
> foo 10
=> [10, [], {}]
> foo 10, 20, 30
=> [10, [20, 30], {}]
> foo 10, 20, 30, d: 40, e: 50
=> [10, [20, 30], {:d=>40, :e=>50}]
> foo 10, d: 40, e: 50
=> [10, [], {:d=>40, :e=>50}]
Unexpected result with splat operator
Because the []=
method applied to hash
takes only one argument in addition to the key (which is put inside the []
part), and a splatted/expanded array, which is in general a sequence of values (which coincidentally happens to be a single element in this particular case) cannot be directly accepted as the argument as is splatted. So it is accepted by the argument of []=
as an array after all.
In other words, an argument (of the []=
method) must be an object, but splatted elements (such as :foo, :bar, :baz
) are not an object. The only way to interpret them as an object is to put them back into an array (such as [:foo, :bar, :baz]
).
Using the splat operator, you can do it like this:
hash.each_pair{|key, value| hash.[]= key, *value}
Map splat arguments over method parameters
def f(params,*args)
# elements to be assigned to splat parameter
splat = args.count - params.count + 1
# will throw an error if splat < 0 as that means not enough inputs given
params.map{ |p|
[ p[1] , ( p.first == :rest ? args.shift(splat) : args.shift ) ]
}
end
Examples
def splatter(x,*y,z)
# some code
end
f(method(:splatter).parameters, 1,2,3,4)
#=>[[:x, 1], [:y, [2, 3]], [:z, 4]]
def splatter(x,y,*z)
# some code
end
f(method(:splatter).parameters, 1,2,3,4)
# => [[:x, 1], [:y, 2], [:z, [3, 4]]]
def splatter(x,*z)
# some code
end
f(method(:splatter).parameters, 1)
# => [[:x, 1], [:z, []]]
Array equation explanation
To break anything down line by line one could use REPL:
*a, b = [1, 2, 3, 4]
#⇒ [1, 2, 3, 4]
a
#⇒ [1, 2, 3]
b
#⇒ 4
Using splat operator, we have decomposed the original array to new array and the single value. Now everything is crystal clear: a[b-2]
which is a[2]
, which is in turn 3
(check a
array.) and b is still 4
.
3 + 4
#⇒ 7
Default arguments with *args and **kwargs
Just put the default arguments before the *args
:
def foo(a, b=3, *args, **kwargs):
Now, b
will be explicitly set if you pass it as a keyword argument or the second positional argument.
Examples:
foo(x) # a=x, b=3, args=(), kwargs={}
foo(x, y) # a=x, b=y, args=(), kwargs={}
foo(x, b=y) # a=x, b=y, args=(), kwargs={}
foo(x, y, z, k) # a=x, b=y, args=(z, k), kwargs={}
foo(x, c=y, d=k) # a=x, b=3, args=(), kwargs={'c': y, 'd': k}
foo(x, c=y, b=z, d=k) # a=x, b=z, args=(), kwargs={'c': y, 'd': k}
Note that, in particular, foo(x, y, b=z)
doesn't work because b
is assigned by position in that case.
This code works in Python 3 too. Putting the default arg after *args
in Python 3 makes it a "keyword-only" argument that can only be specified by name, not by position. If you want a keyword-only argument in Python 2, you can use @mgilson's solution.
What does the (unary) * operator do in this Ruby code?
The *
is the splat operator.
It expands an Array
into a list of arguments, in this case a list of arguments to the Hash.[]
method. (To be more precise, it expands any object that responds to to_ary
/to_a
, or to_a
in Ruby 1.9.)
To illustrate, the following two statements are equal:
method arg1, arg2, arg3
method *[arg1, arg2, arg3]
It can also be used in a different context, to catch all remaining method arguments in a method definition. In that case, it does not expand, but combine:
def method2(*args) # args will hold Array of all arguments
end
Some more detailed information here.
C++ Boost::MPL fold example - wrong number of arguments
You are messing up the namespaces. Making a lot of symbols ambiguous.
Remove the using
and the example works fine for me.
...
using namespace boost;
typedef mpl::vector<long,float,short,double,float,long,long double> types;
typedef mpl::fold<
types
, mpl::int_<0>
, mpl::if_< is_float<boost::mpl::_2>,boost::mpl::next<boost::mpl::_1>,boost::mpl::_1 >
>::type number_of_floats;
...
Related Topics
Ruby, Rails Gem Install Error - Error: While Executing Gem ... (Encoding::Undefinedconversionerror)
Splitting a String into Words and Punctuation with Ruby
How to Serialize a Ruby Digest::Sha1 Instance Object
Rvm Isnt Setting Environment with Cron
Ruby: Automatically Wrapping Methods in Event Triggers
Convert Spreadsheet Column Index into Character Sequence
Rails: Chartkick Cummulative User Graph
404 Resource Not Found: Domain with Google Directory API
Mini_Magick Gem Doesn't Work with My Imagemagick Install
Problems with Jslint-V8 Ruby Gem Installation on Windows7 64-Bit
Integrate Shoes into Aptana Studio Radrails
Ruby: Why Are All Coordinates Getting Updated in an Array of Arrays
How to Reset Boolean to "Default: False" at End of Day
How Does This Block Work for Integer Times Method
Rails Search Query Associated Model
Calling Instance Variables Without @
How to Understand the #Dup and #Clone Operate on Objects Which Referencing Other Objects