2009-10-01 4 views
8

はルビー(面から取られた)でハッシュautovivificationを可能にするための巧妙なトリックです:ルビーハッシュautovivification(面)

# File lib/core/facets/hash/autonew.rb, line 19 
    def self.autonew(*args) 
    leet = lambda { |hsh, key| hsh[key] = new(&leet) } 
    new(*args,&leet) 
    end 

それは(もちろん)動作しますが、私は「それは本当にイライラする私ができることを見つけますこの二人のライナーがどういう仕組みになっているかを理解してください。

リートがデフォルト値として設定されます。だからちょうどh['new_key']にアクセスして何とかそれを持ち出して作成します。h['new_key']は評価するのではなく、デフォルト値オブジェクトを返すと思います。つまり、'new_key' => {}は自動的に作成されません。だから、リートは実際にどのように呼び出されますか?特に2つのパラメータがありますか?

答えて

18

標準new method for Hashはブロックを受け入れます。このブロックは、存在しないハッシュのキーにアクセスしようとした場合に呼び出されます。ブロックは、ハッシュ自体と要求されたキー(2つのパラメータ)を渡され、要求されたキーに対して返される値を返す必要があります。

leetラムダは2つのことを行います。 leetという新しいハッシュをデフォルトを処理するブロックとして返します。これは、autonewが任意の深さのハッシュに対して機能することを可能にする動作です。また、この新しいハッシュをhsh[key]に割り当てます。そのため、次に同じキーを要求すると、新しいハッシュが作成されるのではなく、既存のハッシュが取得されます。

+0

優れた答えです。 – Pesto

+1

それは確かです。これは特に、RubyBook(標準的なルビーのWindowsディストリビューションに付属しています)をもう一度参照しないように教えてくれるのです。なぜなら、ブロックと新しいものについての小さな無関係な事実は言及していないからです。 – artemave

8

それはまた次のようにこのコードはワンライナーにすることができることは注目に値します:#1 default_procをハッシュする

def self.autonew(*args) 
    new(*args){|hsh, key| hsh[key] = Hash.new(&hsh.default_proc) } 
end 

コールは、親の作成に使用されたPROCを返しますので、我々は持っています素敵な再帰的セットアップがここにあります。

私はこのブログについてsimilar caseについて話しています。

-1

また、xkeys gemと考えることもできます。ネストされたアクセスを容易にするために配列やハッシュを拡張するために使用できるモジュールです。

まだ存在していないものを探す場合は、何も表示せずにnil値(または別の値または例外)を取得します。また、配列の最後に追加することもできます。

整数キーのハッシュまたは配列のいずれかを自動更新することができます(構造全体に対して1回のみ)。

関連する問題