Named parameters in Ruby don't work? [duplicat

2019-05-20 22:44发布

This question already has an answer here:

I wonder why named parameters don't work as I expect.

 def my_method(var1, var2 = 1, var3 = 10)
   puts var1, var2, var3
 end

my_method(999, var3 = 123)

The output

999
123
10

instead of (at least, as I guess should be):

999
1
123

So, what should I do to use named parameters?

P.S. When I use the hash, it's not what I'm looking for yet:

def my_method(var1, vars = {var2: 1, var3: 10} )
   puts var1, vars[:var2], vars[:var3]
 end

my_method(999, var3: 123)

999

123


my_method(999, var2: 111, var3: 123)

999
111
123



my_method(999)
999
1
10

So I have to override each value of vars or don't override them at all. Is there any more convenient way?

5条回答
▲ chillily
2楼-- · 2019-05-20 23:20

You can use this

  def my_method(options = {})
   puts options[:var1] || ''
   puts options[:var2] || ''
   puts options[:var3] || ''
  end

call using

my_method(var1:999, var3: 123)

or

my_method(var1:999)
查看更多
Summer. ? 凉城
3楼-- · 2019-05-20 23:23

Ruby 2.0.0 is released, now you can use named parameters.

def my_method(var1, var2: 1, var3: 10)
   puts var1, var2, var3
end

my_method(999, var3: 123)

The result:

999
1
123

Or another example:

def foo(str: "foo", num: 100)
  [str, num]
end

p foo(str: 'buz', num: 1) #=> ['buz', 1]
p foo(str: 'bar') # => ['bar', 100]
p foo(num: 2) # => ["foo", 2]
p foo # => ['foo', 100]
p foo(bar: 'buz') # => ArgumentError
查看更多
爷的心禁止访问
4楼-- · 2019-05-20 23:40

You can also play with something like this:

def method(data)
    defaults = {var2: 1, var3: 10}
    (@var1, @var2, @var3) = defaults.merge(data).values_at(:var1, :var2, :var3)
    p @var1, @var2, @var3
end

method(var1: 999, var3: 123)
查看更多
祖国的老花朵
5楼-- · 2019-05-20 23:43

In ruby my_method(999, var3 = 123) means, assign var3 the value 123 and pass it to my_method.

There is no concept of named parameters, however, you can use a hash as an argument to my_method such as:

def my_method(args = {})
   p "#{args[:a]}, #{args[:b]}, #{args[:c]}"
end

Then you can call it with:

my_method(b: 2, c: 3, a: 1)

which will print 1, 2, 3, because b: 2, c: 3, a: 1 is inferred to be a hash by ruby. You can explicitly indicate the hash as well with:

my_method({b: 2, c: 3, a: 1})
查看更多
Melony?
6楼-- · 2019-05-20 23:47

As pointed out, Ruby does not have keyword arguments (yet, they are coming in 2.0). To achieve what you are trying to do, an options hash is a very common Ruby idiom.

def my_method(var1, options = {})
  var2 = options.fetch(:var2, 1)
  var3 = options.fetch(:var3, 10)

  puts var1, var2, var3
end

my_method(999)
# => 999, 1, 10

my_method(999, var3: 123)
# => 999, 1, 123

my_method(999, var2: 111)
# => 999, 111, 10

my_method(999, var2: 111, var3: 123)
# => 999, 111, 123

my_method()
# => ArgumentError: wrong number of arguments (0 for 1)

Note that using options.fetch(:key, default) rather than options[:key] || default is frequently preferable because it allows you to explicitly specify falsy values (ie false and nil).

options = {x: nil, y: false}

x = options[:x] || 42      # sets x to 42
x = options.fetch(:x, 42)  # sets x to nil

y = options[:y] || 43      # sets y to 43
y = options.fetch(:y, 43)  # sets y to false

z = options[:z] || 44      # sets z to 44
z = options.fetch(:z, 44)  # sets z to 44

You can even pass a block to fetch which allows you to defer computation of the default value:

options.fetch(:x) { some_expensive_calculation }
# some_expensive_calculation is only called if necessary
查看更多
登录 后发表回答