23

私がこのハッシュを持っているとしましょう:

entry = {"director"=>"Chris Nolan", "prducer"=>"Sum Duk", "writer"=>"Saad Bakk"}

各キーを、関連する値を持つ独自のローカル変数に抽出したいと思います。

director = "Chris Nolan"
producer = "Sum Duk"
...

ループを使用するのではなく、次のようにします。

director = entry["director"]

価値観がたくさんあるので、個別にやりたくないです。

インスタンス変数を作成し、ローカル変数が必要なことを除いて、これはほぼ完全に機能することがわかりましたlocal_variable_setが、何らかの理由で存在しません。

entry.each_pair { |k, v| instance_variable_set("@#{k}", v) }

解決策はありますか?または、それが失敗した場合、インスタンス変数をローカル変数に変換し、インスタンスを1つずつ実行せずに1つずつ削除する方法はありますか?

4

4 に答える 4

8

オプション1

私は楽しみを除いてこれをお勧めすることはできませんが、それは主にあなたが求めている効果があります:

entry.each |k, v|
  singleton_class.send(:attr_accessor, k)
  send("#{k}=", v)
end

director                        # => "Chris Nolan"
self.director = "Wes Anderson"  # Unfortunately, must use self for assignment
director                        # => "Wes Anderson"

ローカル変数を作成する代わりに、現在のオブジェクトのシングルトンクラスにアクセサメソッドを定義します。これは、ローカル変数であるかのように呼び出すことができます。

それらをより「ローカル」にするために、それらを使いsingleton_class.remove_method終わったときにこれらのメソッドを削除するために使用できます。同じ名前の既存のシングルトンクラスメソッドのエイリアスを作成して、後で復元することもできます。

オプション2

これは私が実際のコードで使用しているものです。Ruby On Railsに付属しているActiveSupportgemが必要ですが、単独で使用することもできます。

director, producer, writer = entry.values_at('director', 'producer', 'writer')

残念ながら、各変数名を要求どおりに0回ではなく、2回入力する必要があります。ハッシュ内の値の順序がわかっている場合は、次のように記述できます。

director, producer, writer = entry.values  # Not so good, IMO.

ハッシュを作成したコードには、ハッシュが特定の順序になっていることを確認するという明白でない責任があるため、このバージョンには不安を感じます。

ノート

目標がタイピングを減らすことだけである場合、変数アクセスごとに必要な文字数が真のローカル変数である場合よりも2文字多いアプローチを次に示します。

e = OpenStruct.new(entry)
e.director     # => "Chris Nolan"
于 2015-08-14T15:49:10.280 に答える
4

変数スコープのため、ローカル変数を作成できません。
ブロック内にローカル変数を作成すると、その変数にはブロック自体の内部でのみアクセスできます。
詳細については、この質問を参照してください。
Rubyでローカル変数を動的に設定する

于 2012-11-14T15:59:38.977 に答える
4

これはで行うことができますがeval、これらの変数に対するすべての操作は、それらが定義されたスコープ内にある必要があります。

たとえば、これは機能します。

vals = {
  "foo" => "bar",
  "baz" => "qux"
}

eval <<-EOF
  #{ vals.map {|k, v| "#{k} = \"#{v}\""}.join("\n") }
  puts foo
EOF

ただし、これは次のことを行いません。

vals = {
  "foo" => "bar",
  "baz" => "qux"
}

eval <<-EOF
  #{ vals.map {|k, v| "#{k} = \"#{v}\""}.join("\n") }
EOF

puts foo

評価のfoo最後にスコープ外になります。ただし、変数に関するすべての作業をevalのスコープ内で実行できる場合、それは非常に実行可能です。

于 2012-11-14T16:10:58.507 に答える
0

@antinomeのメモを拡張する:ローカル変数を存在させたい場合、たとえば文字列で補間することによって動的にアクセスしたい場合、OpenStruct+instance_evalはこの強力な方法を提供します:

require 'ostruct'
o = OpenStruct.new(entry)
o.instance_eval("Directed by #{director}, produced by #{producer}")
o.instance_eval {
  puts "Directed by #{director}"
  puts "Produced by #{producer}"
}
于 2020-06-16T20:52:43.180 に答える