Ruby Optional Parameters and Multiple Parameters

2019-04-09 17:37发布

问题:

I am trying to set the first argument to a method as being optional, followed by any number of args. For example:

def dothis(value=0, *args)

The issue I am running into is that it doesn't seem like this is actually possible? When I call dothis("hey", "how are you", "good") I was hoping it would set value to default to 0, but instead it is just making value="hey". Is there any way to accomplish this behavior?

回答1:

This is not possible directly in Ruby

There are plenty of options though, depending on what you are doing with your extended params, and what the method is intended to do.

Obvious choices are

1) Take named params using hash syntax

def dothis params
  value = params[:value] || 0
  list_of_stuff = params[:list] || []

Ruby has nice calling convention around this, you don't need to provide the hash {} brackets

dothis :list => ["hey", "how are you", "good"]

2) Move value to the end, and take an array for the first param

def dothis list_of_stuff, value=0

Called like this:

dothis ["hey", "how are you", "good"], 17

3) Use a code block to provide the list

dothis value = 0
  list_of_stuff = yield

Called like this

dothis { ["hey", "how are you", "good"] }

4) Ruby 2.0 introduced named hash parameters, which handle a lot of option 1, above for you:

def dothis value: 0, list: []
  # Local variables value and list already defined
  # and defaulted if necessary

Called same way as (1):

dothis :list => ["hey", "how are you", "good"]


回答2:

This post is a little bit old, but I want to contribute if someone is looking for the best solution for that. Since ruby 2.0, you can do that easily with named arguments defined with a hash. The syntax is easy and more readable.

def do_this(value:0, args:[])
   puts "The default value is still #{value}"
   puts "-----------Other arguments are ---------------------"
  for i in args
    puts i
  end
end
do_this(args:[ "hey", "how are you", "good"])

You can also do the same thing with the greedy keyword **args as a hash, like this:

#**args is a greedy keyword
def do_that(value: 0, **args)
  puts "The default value is still #{value}"
  puts '-----------Other arguments are ---------------------'
  args.each_value do |arg|
    puts arg
  end
end
do_that(arg1: "hey", arg2: "how are you", arg3: "good")


回答3:

You will need to use named parameters to accomplish this:

def dothis(args)
  args = {:value => 0}.merge args
end

dothis(:value => 1, :name => :foo, :age => 23)
 # => {:value=>1, :name=>:foo, :age=>23} 
dothis(:name => :foo, :age => 23)
 # => {:value=>0, :name=>:foo, :age=>23}


回答4:

by using value=0 you are actually assigning 0 to value. just to retain the value, you can either use the above mentioned solutions or just simply use value everytime you call this method def dothis(value, digit=[*args]).

The default arguments are used when the arguments are not provided.

I came across the similar issue and I got over it by using:

def check(value=0, digit= [*args])
puts "#{value}" + "#{digit}"
end 

and simply call check like this:

dothis(value, [1,2,3,4])

your value would be default and other values belong to other argument.