3

Ruby の新しい安全なナビゲーション演算子 () に関して、私が見つけることができるすべての質問 ( Q1Q2 ) への回答は、それが と同等であると&.誤って宣言しています。obj&.fooobj && obj.foo

この等価性が正しくないことを示すのは簡単です:

obj = false
obj && obj.foo  # => false
obj&.foo        # => NoMethodError: undefined method `foo' for false:FalseClass

また、多重評価の問題もある。副作用のある式に置き換えるobjと、式でのみ副作用が 2 倍になることがわかり&&ます。

def inc() @x += 1 end

@x = 0
inc && inc.itself  # => 2

@x = 0
inc&.itself        # => 1

obj&.fooこれらの問題を回避する最も簡潔な2.3より前の同等物は何ですか?

4

2 に答える 2

1

try!Ruby 2.3 のセーフ ナビゲーション オペレータは、ActiveSupport によって追加されたメソッドとほぼ同じように機能しますが、そのブロック処理は異なります。

簡略化したバージョンは次のようになります。

class Object
  def try(method, *args, &block)
    return nil if self.nil?
    public_send(method, *args, &block)
  end
end

これを次のように使用できます

obj.try(:foo).try(:each){|i| puts i}

このtryメソッドは、次のような安全なナビゲーション オペレーターのさまざまな詳細を実装します。

  • クエリされたメソッドを実際に実装しているかどうかに関係なくnil、受信者が である場合は常に返されます。nilnil
  • NoMethodErrornilレシーバーがメソッドをサポートしていない場合は、 a が発生します。
  • メソッド呼び出しの例外を飲み込みません。

言語セマンティクスの違いにより、次のようなリアルセーフ ナビゲーション オペレータの他の機能を (完全に) 実装することはできません。

  • try安全なナビゲーション演算子とは対照的に、私たちのメソッドは常に追加の引数を評価します。この例を考えてみましょう

    nil&.foo(bar())
    

    ここでbar()は、評価されません。私たちのtry方法を

    nil.try(:foo, bar())
    

    後でメソッドを呼び出すかどうかに関係なく、常にbar最初にメソッドを呼び出しfooます。

  • obj&.attr += 1Ruby 2.3.0 では有効な構文であり、以前の言語バージョンでは単一のメソッド呼び出しだけではエミュレートできません。

このコードを本番環境で実際に実装する場合は、コア クラスにパッチを適用するのではなく、改良点を確認する必要があることに注意してください。

于 2016-01-05T12:27:33.487 に答える
0

安全なトラバーサル オペレーターがエミュレートする最も類似した方法は、Rails の方法だと思いますtry。ただし、正確ではありませんが、オブジェクトがメソッドに応答しないだけでなく、メソッドに応答しない場合を処理する必要がありますnil

メソッドが指定されたメソッドを評価できない場合、nil を返します。

try次のようにかなり簡単に書き直すことができます。

class Object
  def try(method)
    if !self.respond_to?(method) && !self.nil?
      raise NoMethodError, "undefined method #{ method } for #{ self.class }"
    else
      begin
        self.public_send(method) 
      rescue NoMethodError
        nil
      end
    end
  end
end

その後、ほぼ同じ方法で使用できます。

Ruby 2.2 以前:

a = nil
a.try(:foo).try(:bar).try(:baz)
# => nil

a = false
a.try(:foo)
# => NoMethodError: undefined method :foo for FalseClass

Ruby 2.3 で同等

a = nil
a&.foo&.bar&.baz
# => nil

a = false
a&.foo
# => NoMethodError
于 2016-01-05T00:22:12.233 に答える