什么是Ruby2.3前相当于安全导航操作符(&.或 "安培点")?

问题描述 投票:3回答:2

我所能找到的每个问题的答案(Q1, Q2),关于Ruby新的安全导航操作员(&.)误称 obj&.foo 相当于 obj && obj.foo.

很容易证明这种等价关系是不正确的。

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

此外,还有一个多重评价的问题。取代 obj 与具有副作用的表达式一起,显示出只有在 && 的表达方式。

def inc() @x += 1 end

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

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

什么是2. 3之前最简洁的等价物?obj&.foo 的方法来避免这些问题?

ruby null operators ruby-2.3 safe-navigation-operator
2个回答
1
投票

在Ruby 2.3中,安全导航操作符的工作原理几乎与Ruby 2.3中的 try! 方法,减去其块处理。

一个简化版的方法可以是这样的。

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 如果接收器是 nil,无论 nil 是否真正实现了被查询的方法。
  • 它引发了一个 NoMethodError 如果非nil 接收器不支持该方法。
  • 它不吞噬任何方法调用上的异常。

由于语言语义的不同,它不能(完全)实现真正的安全导航操作符的其他功能,包括。

  • 我们的 try 方法总是评估额外的参数,这与安全导航操作符不同。请看这个例子

    nil&.foo(bar())
    

    给你 bar() 不被评估。当使用我们的 try 方法为

    nil.try(:foo, bar())
    

    我们总是称 bar 方法,不管我们后来是否调用 foo 与否。

  • obj&.attr += 1 是Ruby 2.3.0中的有效语法,这在以前的语言版本中不能只用一个方法调用来模拟。

需要注意的是,当你在生产中真正实现这段代码时,你应该看一看 完善 而不是给核心类打补丁。


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
© www.soinside.com 2019 - 2024. All rights reserved.