2016-05-23 4 views
0

Rubyでは、の2つのの4つのケースで違いがありますか?もしそうなら、どちらがより良い方法ですか?インスタンスを返すためのRubyのベストプラクティスは、定義されていない可能性があります

class OptionOne 
    def initialize(arr) 
    @arr = arr 
    end 
    def arr 
    @arr || [] 
    end 
end 

class OptionTwo 
    def initialize(arr) 
    @arr = arr 
    end 
    def arr 
    (defined? @arr) ? @arr : [] 
    end 
end 

第三の選択肢、イリヤが言及したのRubyスタイルガイドにしたがって:

class OptionThree 
    def initialize(arr) 
    @arr = arr 
    end 
    def arr 
    @arr ||= [] 
    end 
end 

そしてキース・ベネットからの回答から4番目のオプション:

class OptionFour 
    attr_accessor :arr 
    def initialize(arr = []) 
    @arr = arr 
    end 
end 
+0

'@ arr'行で何をしようとしていますか? –

+1

このコードでは、@arrを値で初期化する方法はありませんので、@arrは常にnil(定義されていません)になります。また、OptionOne#arrでは、 '@ arr'(「@」に注意してください)と言う必要があります。それ以外の場合、スタックオーバーフローが発生するまで関数は自身を呼び出します。 –

+0

変数が初期化されている空の配列の場合は、コンストラクタで初期化をしないでください。遅延初期化(遅延が必要になるまで初期化を延期する)の値は、初期化が高価な場合(時間、メモリ、その他のリソースなど)に発生します。 –

答えて

5

注:元の質問に対する答えです。

def arr 
    @arr ||= [] 
end 

a ||= ba || a = bのためだけの速記:ルビーstyle guide、より有効に活用memoizationによると

。さらに詳しくhere

+0

アドバイスありがとう(本当に便利なリンク)。だから、編集された質問の中のOptionThreeは使えるものでしょうか? –

+0

もしあれば、 'a || = b'は' a || a = b'(つまり、 'a'は偽であれば設定されます)。しかし、 '|| ='はアクセサメソッド、ハッシュ、配列などを使うときにはまだ異なります。いずれにせよ、 'a'は一度だけ評価されます。ありがとう、@HolgerJust。 –

+0

私は私の答えを更新しました、それはあなたからの非常に有用な情報でした。 – Ilya

1

結果のオブジェクトで何をしたいかによって異なります。

@arrがどこかの値に設定されていないと、あなたのオプションは常に新しいオブジェクトを返します。これにより、この値がOptionOneインスタンスの状態に影響しないことが保証されます。 OptionThreeの主な違いは、この場合の動作である:OptionThreeため

option_one = OptionOne.new(nil) 
arr = option_one.arr 
arr[0] = "Hello" 

arr 
# => ["Hello"] 
option_one.arr 
# => [] 

対:OptionThreeの場合

option_three = OptionThree.new(nil) 
arr = option_three.arr 
arr[0] = "Hello" 

arr 
# => ["Hello"] 
option_three.arr 
# => ["Hello"] 

、単一の配列オブジェクトは、オプションのオブジェクトに保存されているであろう後のコードで変更可能です。 OptionOneの場合、常に新しいArrayオブジェクトが返されます。

@arrがまだtruethy値(たとえば配列)で初期化されていない場合にのみ、この区別が成立することに注意してください。その場合、両方の変種はOptionThreeの動作を示します。多くの場合、同じ動作を保つためにOptionThreeが実装されていることがよくあります。

オプションオブジェクトの内部状態を常に保持することがわかっている場合は、毎回新しいオブジェクトを返すのが理にかなっています。

OptionTwoになりましたが、これは機能しません。イニシャライザで常に@arrを設定するので、常に設定され、したがって返されます。したがって、else部分は決して実行されません。インスタンス変数とdefined?を使用すると、ほとんど常に悪い考えであることを

def OptionTwo 
    def initialize(arr) 
    @arr = arr 
    end 

    attr_reader :arr 
end 

注:お使いのOptionTwoは、このように短縮することができます。 Rubyでは、インスタンス変数は暗黙的に多くの場合に初期化されます。どこにでもそれを読んでいるとき(前に明示的な値に設定されていたかどうかは関係ありません)。したがって、defined?の振る舞いに頼っているときは、間違って定義しないように注意する必要があります。しばしば、それが定義されていると仮定し、その値に基づいて振る舞いを処理する方がずっと便利です。

nilfalse@arrの有効な値でない場合は、いつでも安全に||=を使用してアレイにそれを初期化することができます。これらのどれかが有効な値である場合、正しい初期化を選択するために追加のロジックを追加する必要があります。

+0

非常に洞察力のある答えをありがとう。さまざまなオプションの字幕が表示されます。 –

関連する問題