1

ルビーで古い「エラーレジュームネクスト」ルーチンを実行する方法はありますか?

他の場所から動的に値の配列を入力し(正確にはMQTTトピックから読みます)、それらに対して一連の数値計算を実行して結果を公開したいと思います。値は数値である必要がありますが、欠落しているか、数値ではない可能性があります。

現時点では、私のコードは次のようになっています

values=[]


//values get loaded here 

begin
  Publish('topic1',value[0]*10+value[1])
rescue TypeError,NoMethodError,ZeroDivisionError
end

begin
  Publish('topic2',value[3]/value[4])
rescue TypeError,NoMethodError,ZeroDivisionError
end

//etc etc

何らかの理由で計算が失敗した場合、プログラムはそのステップをスキップして続行する必要があります。

それは機能しますが、確かにそれらすべての同一のbegin..rescueブロックよりも良い方法がありますか?Rubyは結局「DRY」についてです。

上記を書き直して、すべての計算を試行できるようにしながら、単一のbegin..rescueコンストラクトが使用されるようにする方法はありますか?

更新しました

次のようなことをするのはどれほど安全か

def safe_Publish(topic,value)
  return if value.nil?
  Publish(topic,value)
end

safe_Publish('topic2'、(value [3] / value [4]rescue nil))で呼び出します

主な問題は、上記が私が期待しているものだけでなくすべての例外をキャッチすることであり、それは私を少し緊張させます。

4

3 に答える 3

1

コーディング スタイルは非常に危険です。on error resume next誤ってプログラムに導入した新しいバグを見つけるのが非常に困難になるからです。代わりに、これらの例外をスローしない別のバージョンのパブリッシュを作成します。

def try_publish(topic_name)
  begin
    Publish('topic1',yield)
  rescue TypeError,NoMethodError,ZeroDivisionError
    # are you sure you don't want to do anything here? Even logging the errors
    # somewhere could be useful.
  end
end

次に、これを次のように呼び出すことができます。

try_publish('topic1') { value[0]*10+value[1] }

TypeError、NoMethodError、または ZeroDivisionError が式によってスローされた場合、それらはキャッチされて無視されます。

これで、元の方法ではレスキューは必要ありません。


本当に が必要な場合on error resume nextは、カーネルのメソッドにモンキー パッチを適用することで実現できますが、raiseそれは恐ろしい考えです。

于 2012-06-29T05:50:35.487 に答える
0

これは、begin/rescue によって保護された一連のクイック操作をループにラップする方法を示しています。

values = [1,2,3,0,4]
ops = [ ->{values[0]/values[1]}, ->{values[2]/values[3]} ]

ops.each do |op|
  begin
    puts "answer is #{op.call}"
  rescue ZeroDivisionError
    puts "cannot divide by zero"
  end
end

safe_publishただし、単体テストを実行でき、安全な呼び出しを行い、エラーを処理するロジックを 1 か所にカプセル化できるため、この方法を好みます。

def safe_publish(topic, &block)
  begin
    value = block.call
    publish(topic, value)
  rescue
    # handle the error
  end
end

そして、次のようなコードでこれを呼び出すことができます:

safe_publish 'topic0' do
  value[0]*10+value[1]
end
于 2012-06-29T05:33:31.633 に答える
0

自分が何をしているのか、なぜが必要なのかをもう少し注意深く考えると、すべての例外on error resume nextを抑制する必要がないことがわかると思います。他の投稿者が指摘したように、バグを見つけて修正するのが難しくなります。

あなたの問題は、インターネットから集めたたくさんの数字があり、それらに対していくつかの計算を実行したいが、一部が無効または欠落している可能性があることです。無効または欠落している数値については、それらの数値を使用する計算をスキップする必要があります。

いくつかの可能な解決策:

  1. データを事前にフィルタリングし、有効な数値ではないものをすべて削除します。
  2. 実行する各計算を独自のメソッドに入れます。rescue Exceptionメソッド定義にaを付けます。
  3. ゼロ除算などで例外を発生させない数値クラスの「安全な」ラッパーを定義します。これらのラッパーを計算に使用します。

「ラッパー」は次のようになります (完全でテスト済みのコードを期待しないでください。これはアイデアを提供するためのものです)。

# This is not designed for "mixed" arithmetic between SafeNumerics and ordinary Numerics,
# but if you want to do mixed arithmetic, that can also be achieved
# more checks will be needed, and it will also need a "coerce" method
class SafeNumeric
  attr_reader :__numeric__
  def initialize(numeric)
    @__numeric__ = numeric.is_a?(String) ? numeric.to_f : numeric
  end

  def zero?
    @__numeric__.zero?
  end
  def /(other)
    if other.zero? || @__numeric__.nil? || other.__numeric__.nil?
      SafeNumeric.new(nil) # could use a constant for this to reduce allocations
    else
      SafeNumeric.new(@__numeric__ / other.__numeric__)
    end
  end

  def to_s; @__numeric__.to_s; end
  def inspect; @__numeric__.inspect; end

  # methods are also needed for +, -, *
end

次に、次のように使用します。

numbers = scraped_from_net.map { |n| SafeNumeric.new(n) }
# now you can do arithmetic on "numbers" at will
于 2012-06-29T06:47:26.917 に答える