当接收器为零时,Ruby 安全导航运营商是否评估其参数?

Mar*_*n13 4 ruby safe-navigation-operator

题:

Ruby 安全导航操作符 ( &.) 是否在其接收器为 时评估其参数nil

例如:

logger&.log("Something important happened...")
Run Code Online (Sandbox Code Playgroud)
  • "Something important happened..."字符串是在这里求值的吗?
  • 您能否提供一个权威来源,证明或否认这一事实?
  • 或者建议一种如何检查它的方法?

提前致谢。




为什么我要寻找这个问题的答案?

我的代码库中有如下代码:

logger&.log("Something important happened...")
Run Code Online (Sandbox Code Playgroud)

我的主要目标是if verbose在我调用该log方法时消除重复检查,因为很容易忘记它,并且您根本不会收到有关误用的通知。

Tell启发,不问原则,

我已经if verboselog方法实现中移动了检查。

logger.log("Something important happened. (#{Time.current})") if verbose
Run Code Online (Sandbox Code Playgroud)

这种方法简化了我的代码,因为我已经解决了我的主要问题 -if verbose每次调用该log方法时我都不需要记住放置,

但我收到了另一个问题。

"Something important..."字符串总是被评估,无论verbosetrue还是false

因此,我彻底改变了解决方案:

  • logger返回nilverbosefalse
  • Ruby 安全导航操作符应该在log调用前使用。
class Logger
  # ...
  
  def log(message)
    return unless verbose

    # ...
  end
end

def logger
  @logger ||= Logger.new
end

logger.log("Something important happened. (#{Time.current})")
Run Code Online (Sandbox Code Playgroud)

结果,我已经将记住if verbose检查的最初问题替换为记住&.电话。

但是,无论如何,我认为这是一种改进,因为忘记使用安全导航操作符会引发NoMethodError,换句话说,通知log方法误用。

所以现在,为了确保“安全导航操作员方法”实际上是解决我的问题的“更好”选择,

我需要确切地知道 Ruby 中的安全导航操作符是否在其接收器为nil.

Hol*_*ust 5

引用安全导航操作符的语法文档

&.,称为“安全导航操作符”,允许在接收者为 时跳过方法调用nil如果跳过调用,它会返回nil并且不评估方法的参数。

因此,您的参数log方法不被评估,如果loggernil,当你把它作为

logger&.log("something happened at #{Time.now}")
Run Code Online (Sandbox Code Playgroud)

话虽如此,请注意 Ruby 核心记录器为您的确切问题提供了不同的解决方案,即避免在日志级别过高时评估潜在的昂贵参数。

Ruby 核心记录器实现其add方法如下(简化):

class Logger
  attr_accessor :level

  def initialize(level)
    @level = level.to_i
  end

  def add(severity, message = nil)
    return unless severity >= level
    
    message ||= yield
    log_device.write(message)
  end

  def info(message = nil, &block)
    add(1, message, &block)
  end
end
Run Code Online (Sandbox Code Playgroud)

然后您可以将其用作

logger = Logger.new(1)
logger.info { "something happened at #{Time.now}" }
Run Code Online (Sandbox Code Playgroud)

在这里,只有当日志级别足够高以至于实际使用消息时才会评估块。