33

私はRubyonRailsで遊んでいて、オプションのパラメーターを使用してメソッドを作成しようとしています。どうやらそれを行うには多くの方法があります。オプションのパラメーターにハッシュとして名前を付けて、定義せずに試しました。出力が異なります。見てください:

# This functions works fine!
def my_info(name, options = {})
    age = options[:age] || 27
    weight = options[:weight] || 160
    city = options[:city] || "New York"
    puts "My name is #{name}, my age is #{age}, my weight is #{weight} and I live in {city}"
end


my_info "Bill"
-> My name is Bill, my age is 27, my weight is 160 and I live in New York
-> OK!

my_info "Bill", age: 28
-> My name is Bill, my age is 28, my weight is 160 and I live in New York
-> OK!

my_info "Bill", weight: 200
-> My name is Bill, my age is 27, my weight is 200 and I live in New York
-> OK!

my_info "Bill", city: "Scottsdale"
-> My name is Bill, my age is 27, my weight is 160 and I live in Scottsdale
-> OK!

my_info "Bill", age: 99, weight: 300, city: "Sao Paulo"
-> My name is Bill, my age is 99, my weight is 300 and I live in Sao Paulo
-> OK!

****************************

# This functions doesn't work when I don't pass all the parameters
def my_info2(name, options = {age: 27, weight: 160, city: "New York"})
    age = options[:age]
    weight = options[:weight]
    city = options[:city]
    puts "My name is #{name}, my age is #{age}, my weight is #{weight} and I live in #{city}"
end

my_info2 "Bill"
-> My name is Bill, my age is 27, my weight is 160 and I live in New York
-> OK!

my_info2 "Bill", age: 28
-> My name is Bill, my age is 28, my weight is  and I live in 
-> NOT OK! Where is my weight and the city??

my_info2 "Bill", weight: 200
-> My name is Bill, my age is , my weight is 200 and I live in 
-> NOT OK! Where is my age and the city??

my_info2 "Bill", city: "Scottsdale"
-> My name is Bill, my age is , my weight is  and I live in Scottsdale
-> NOT OK! Where is my age and my weight?

my_info2 "Bill", age: 99, weight: 300, city: "Sao Paulo"
-> My name is Bill, my age is 99, my weight is 300 and I live in Sao Paulo
-> OK!

オプションパラメータの2番目のアプローチの何が問題になっていますか?2番目の方法は、オプションのパラメーターを渡さない場合、またはすべてを渡した場合にのみ機能します。

私は何が欠けていますか?

4

11 に答える 11

58

オプションの引数がrubyで機能する方法は、等号を指定することです。引数が渡されない場合は、指定したものが使用されます。したがって、2番目の例で2番目の引数が渡されない場合は、

{age: 27, weight: 160, city: "New York"}

使用されている。最初の引数の後にハッシュ構文を使用すると、その正確なハッシュが渡されます。

あなたができる最善のことは

def my_info2(name, options = {})
  options = {age: 27, weight: 160, city: "New York"}.merge(options)
...
于 2012-04-19T18:32:02.633 に答える
16

問題は、投稿した2番目のバージョンのデフォルト値がoptions全体であるということです。Hashしたがって、デフォルト値である全体Hashが上書きされます。これがデフォルト値をアクティブにするため、何も渡さないのはそのためです。デフォルト値を同じキーHashで上書きするため、すべてを入力することもできます。Hash

Arrayメソッド呼び出しの最後にあるすべての追加オブジェクトをキャプチャするためにを使用することを強くお勧めします。

def my_info(name, *args)
  options = args.extract_options!
  age = options[:age] || 27
end

Railsのソースを読んで、このトリックを学びました。ただし、これはActiveSupportを含める場合にのみ機能することに注意してください。または、ActiveSupport gem全体のオーバーヘッドが必要ない場合は、に追加された2つのメソッドを使用するだけHashArray、これが可能になります。

rails / activesupport / lib / active_support / core_ext / array / extract_options.rb

したがって、メソッドを呼び出すときは、追加のオプションを使用する他のRailsヘルパーメソッドと同じように呼び出します。

my_info "Ned Stark", "Winter is coming", :city => "Winterfell"
于 2012-04-19T18:51:50.313 に答える
9

オプションハッシュの値をデフォルトにする場合は、関数のデフォルトをマージします。デフォルトをデフォルトパラメータ自体に入れると、上書きされます。

def my_info(name, options = {})
  options.reverse_merge!(age: 27, weight: 160, city: "New York")

  ...
end
于 2012-04-19T18:29:35.410 に答える
5

2番目のアプローチでは、あなたが言うとき、

my_info2 "Bill", age: 28

{年齢:28}を通過し、元のデフォルトハッシュ{年齢:27、体重:160、都市:"ニューヨーク"}全体が上書きされます。そのため、正しく表示されません。

于 2012-04-19T18:34:49.457 に答える
4

キーワード引数を使用してメソッドシグネチャを定義することもできます(この質問は古いため、Ruby 2.0以降の新機能)。

def my_info2(name, age: 27, weight: 160, city: "New York", **rest_of_options)
    p [name, age, weight, city, rest_of_options]
end

my_info2('Joe Lightweight', weight: 120, age: 24, favorite_food: 'crackers')

これにより、次のことが可能になります。

  • オプションのパラメーター(:weightおよび:age
  • デフォルト値
  • パラメータの任意の順序
  • ダブルスプラットを使用してハッシュに収集された追加の値(:favorite_foodで収集rest_of_options
于 2016-02-07T22:19:33.957 に答える
3

ハッシュのデフォルト値には、これを使用する必要があります

def some_method(required_1, required_2, options={})
  defaults = {
    :option_1 => "option 1 default",
    :option_2 => "option 2 default",
    :option_3 => "option 3 default",
    :option_4 => "option 4 default"
  }
  options = defaults.merge(options)

  # Do something awesome!
end
于 2012-04-19T18:28:39.290 に答える
3

「なぜ?」という質問に答えるには、関数を呼び出す方法、

my_info "Bill", age: 99, weight: 300, city: "Sao Paulo"

実際にやっています

my_info "Bill", {:age => 99, :weight => 300, :city => "Sao Paulo"}

2つのパラメータとハッシュオブジェクトを渡していることに注意してください"Bill"。これにより、指定したデフォルトのハッシュ値my_info2が完全に無視されます。

他の回答者が言及したデフォルト値のアプローチを使用する必要があります。

于 2012-04-19T18:38:28.697 に答える
3

#fetchあなたの友だちです!

class Example
  attr_reader :age
  def my_info(name, options = {})
    @age = options.fetch(:age, 27)
    self
  end
end

person = Example.new.my_info("Fred")
puts person.age #27
于 2012-04-19T18:41:40.080 に答える
1

または演算子を使用してデフォルトを設定しても問題はありません。これが実際の例です(注、レールのimage_tag方法を使用します):

ファイル:

def gravatar_for(user, options = {} )   
    height = options[:height] || 90
    width = options[:width] || 90
    alt = options[:alt] || user.name + "'s gravatar"

    gravatar_address = 'http://1.gravatar.com/avatar/'

    clean_email = user.email.strip.downcase 
    hash = Digest::MD5.hexdigest(clean_email)

    image_tag gravatar_address + hash, height: height, width: width, alt: alt 
end

コンソール:

2.0.0-p247 :049 > gravatar_for(user)
 => "<img alt=\"jim&#39;s gravatar\" height=\"90\" src=\"http://1.gravatar.com/avatar/<hash>\" width=\"90\" />" 
2.0.0-p247 :049 > gravatar_for(user, height: 123456, width: 654321)
 => "<img alt=\"jim&#39;s gravatar\" height=\"123456\" src=\"http://1.gravatar.com/avatar/<hash>\" width=\"654321\" />" 
2.0.0-p247 :049 > gravatar_for(user, height: 123456, width: 654321, alt: %[dogs, cats, mice])
 => "<img alt=\"dogs cats mice\" height=\"123456\" src=\"http://1.gravatar.com/avatar/<hash>\" width=\"654321\" />" 

クラスを呼び出すときにinitializeメソッドを使用するのと同じように感じます。

于 2014-01-27T17:26:29.377 に答える
1

なぜnilを使用しないのですか?

def method(required_arg, option1 = nil, option2 = nil)
  ...
end
于 2014-05-08T18:38:32.483 に答える
0

ActiveRecordモデルにはmethod_missingメソッドがあり、これをオーバーライドして、クラスが動的に呼び出しに直接応答するようにすることができます。これが素敵なブログ投稿です。

于 2012-04-19T18:35:23.250 に答える