2016-08-30 17 views
1

冗長呼び出しを減らすために、|| =演算子を使用することがよくあります。私は意味がありませんselfを割り当て、このインスタンス変数内にオブジェクト変数を代入する

@my_variable ||= my_calculation_method 

ようなものを取ると、このアイデアあなたは既に推測しているかもしれませんが

class Object 
    def assign 
     if self.instance_of? NilClass 
      self = yield 
     end 
    end 
end 

を使用して

@my_variable.assign { code_block } 

にそれを変えたいというまくいかない。

assignメソッド内の@my_variableポインタにアクセスして値を変更するにはどうすればよいですか?

+0

if self.instance_ofを置き換えることができますか? 'nilClass'(' self.'は必要ありません、btw)は 'if nil? 'とします。 ([Object#nil?](http://ruby-doc.org/core-2.3.0/Object.html#method-i-nil-3F)を参照してください。) 'Object'の多くのサブクラスでは、すべてあなたは '' nilならyieldを置き換える 'と書くことができます。 –

答えて

3

self = xは完全に不可能です。オブジェクトが何であるかを決して変更することはできません。それが特定のクラスで作成された場合、それはまったく同じクラスで終了します。あなたができることは、そのオブジェクトまたはそれに関連するクラスを変更することですが、そのオブジェクトのクラスは不変です。

@xは単に変数にすぎないため、オブジェクトへのポインタです。これは再割り当てできるものです。 @x = zはオブジェクトを変更しないとポインタを変更するだけです。 selfは特殊なケースです。操作しているコンテキストを参照しており、再割り当てできません。あなたのself = yield呼び出しはあなたがnilプログラム全体が何であるかを再定義したい成功したいくつかのまぐれことであれば

は覚えておいてください。

この全面的な努力が間違っていますが、この時点で||=パターンはかなり慣れ親しんだルビーです。あなたがそのパターンを改善したいなら、あなたがやりたいことはいくらかalternative to memoizeを作ることです。

+0

「不可能」より「完全に不可能」は少ないでしょうか? –

+0

ルビーには、実行することを考えるのは単に夢中になる「不可能な」ものがたくさんあります。例: '+'と '-'が数値に対して何を意味するかを再定義する、' 'true''を' '検査する' 'と表示する。 – tadman

5

あなたの初期化ロジックが非自明であると(私は仮定し、質問の前提だった)複数の行にまたがる場合は、ここでは慣用的なルビーでは、あなたが何ができるかです:

@my_variable ||= begin 
    # code block 
end 

通常、私は何ロジックを2つに分割しています。 Memoizationは計算から分離されています。これはあなたの最初の行にあります。

def stats 
    @stats ||= compute_stats 
end 

def compute_stats 
    ... 
end 

このパターンのXXX + compute_XXXは、認識しやすく、フォローするのが簡単です。

2

タドマンは言う通り、self =を書くことはできません。しかし、インスタンス変数の名前を取り、それを設定するメソッドを書くことができます。

あなたは、これが「エレガントでない」または「間違っている」というコメントがあります。私はこの判断を分かち合いませんが、可能な限り標準的な慣習を使用する控え目なコードを書くのは良い習慣です。これにより、他の人があなたのコードを簡単に理解するのに役立ちます。私。 ||=のような基本的なルビーメソッドの代替構文を書くのはおそらく生産的ではありません。どのように動作するかを理解するために、他の人がコードを掘り下げなければなりません。

言われていること、Rubyはあなたがやりたいようにする方法を教えるの利益のために、私は、この目的のために、このObject方法を提案することができます:

class Object 
    def assign(key) 
     # make sure the key is a valid instance variable 
     unless key =~ /^[A-Za-z0-9\_]+$/ 
     raise ArgumentError, "#{key} is not a valid ivar name" 
     end 

     if instance_variable_get("@#{key}").nil? 
     instance_variable_set("@#{key}", yield) 
     end 
    end 
end 

# example 
class Foo 
    def set_bsd 
    assign("bsd", yield) 
    end 
end 
foo = Foo.new 
foo.assign("my_ivar") { "val" } 
foo 
# => #<Foo:0x007fc2e4ccaca0 @asd=1> 
foo.set_bsd { 2 } 
foo 
# => #<Foo:0x007fc2e4ccaca0 @asd=1 @bsd = 2> 

を私はObjectをパッチに対して推薦するが、このように、それはあまりにも一般的なクラスであり、意図しない内部的な機能との競合を引き起こす可能性があります。むしろ、この機能をカスタムクラス/モジュールに追加し、includeモジュールを継承するか、クラスを継承します。

+2

それはあなたが与えている大きな銃です:) –

+1

私はこの種の重手のパッチを当てることは悪い習慣であると思いますが、あなたには真実の勇敢さに+1を与えます。 '^ A 'と' $'の対応部分が改行を区別しているので、あなたの正規表現で '\ A'と' \ z'を試してみてください。式は '\ A \ w + \ z'でなければなりません。' \ w'は '[a-zA-Z0-9_]'の省略形です。 – tadman

+0

FYI正規表現は過度に厳密です。例えば、 '@'は正当なインスタンス変数です。 –

関連する問題