安全导航操作符(孤独运算符)无法处理哈希

时间:2017-10-30 14:50:23

标签: ruby

我正在尝试使用安全导航操作符&来选择性地调用可能是散列或[]的变量的nil方法。据我所知,这就是安全导航操作员的用途。

my_hash = nil
puts "hello, #{ my_hash&[:test] }"
my_hash = { test: "world" }
puts "hello, #{ my_hash&[:test] }"

我希望这能输出:

hello, false
hello, world

但是它不适用于哈希;相反,我得到:

hello, false
undefined method `&` for `{:test=>"world"}:Hash` (NoMethodError)

我做错了什么?

4 个答案:

答案 0 :(得分:4)

因为这个

my_hash[:test]

是这个的语法糖

my_hash.[](:test)

所以这应该有用

my_hash&.[](:test) 

但是它并不漂亮,我知道。

答案 1 :(得分:1)

  

我正在尝试使用&来选择在哈希上调用[]方法,该方法可能是nil,也可能不是。{/ p>

为此,您需要直接调用[] 方法hash[:key]实际上是在哈希上调用:[]方法:

# This will not work:
my_hash&[:test]

# This will:
my_hash&.[](:test)

这显然不是最漂亮的解决方案,但是......您可能希望在方法(return if my_hash.nil?)中使用保护子句,或者执行以下操作:

my_hash.to_h[:test]

答案 2 :(得分:0)

您的问题是没有“安全导航操作员&”这样的东西。

所谓的安全导航操作符是&.。你的代码中没有任何地方:

my_hash&[:test]

是否有安全导航操作员&.

答案 3 :(得分:-3)

TL; DR

您的程序中存在逻辑和语法错误,包括:

  • 像空哈希一样处理nil(NilClass的一个实例)。
  • 误解了nil("")插值返回的内容。
  • 使用安全导航操作符(&.)时的语法错误。

在下面的部分中,我解决了您的逻辑错误,并提供了一些使用本机Hash方法的建议,这些方法可以实现您所寻找的结果,而不会无声地吞噬错误,这些错误会更多地关注代码中有问题的部分。

这个答案的目标不仅仅是指出错误,还要展示如何成功完成你想要做的事情。您的里程可能会有所不同。

修复逻辑错误

原始问题中存在一些关键逻辑错误。如果您希望在Hash值不存在时返回“false”进行插值,请使用#fetch。例如:

hash = {}
hash.fetch :test, false
#=> false

然而,有一个重要的警告。 如果在nil上调用,Hash #fetch将引发NoMethodError,因为nil不响应fetch:

nil.respond_to? :fetch
#=> false

是问题安全导航旨在处理:缺少方法。因此,如果您吞下异常而不是通过#method_missing来拯救它或处理它,那么使用安全导航是有意义的。例如:

hash = nil
hash.fetch :test, false
#=> NoMethodError: undefined method `fetch' for nil:NilClass

hash&.fetch :test, false
#=> nil

但是,这样做基本上会导致以hash.fetch :test rescue false的方式静默地吞下错误,所以这通常是错误的,因为它隐藏了一个逻辑问题或者你已经得到的事实看到一个意想不到的对象,比如nil,而不是空的哈希。但是,它肯定会解决您的插值问题:

hash = nil
"#{hash.fetch :test rescue false}"
#=> "false"

对于你发布的代码,我强调你可能想要使用合理的Hash方法默默地吞下异常,但你的真实世界里程肯定会有所不同。

不需要安全导航器;使用现有的哈希方法

您的原始问题中似乎至少有其他四个相关问题:

  1. 安全导航操作符为&.,因此它仅适用于使用虚线表示法的方法。 my_hash&[:test]不是有效的构造。
  2. 安全导航器处理缺少给定方法的对象。但是,Hash#[]存在,所以即使解析器认为Hash&.[]是一个有效的构造(它没有),这也不会达到你所期望的那样。
  3. 您可能需要Hash#fetchHash#values_at,具体取决于哈希的预期结构和您要返回的对象。
  4. 当您在nil上使用字符串插值时,您隐式调用#to_s。但nil.to_s没有按你的想法行事;它返回一个空字符串,而不是FalseClass的实例。为了证明,请考虑"#{nil}" #=> ""
  5. 相关散列方法的示例

    请考虑以下示例:

    hash = {}
    
    hash.fetch :test
    #=> KeyError: key not found: :test
    
    hash.fetch :test, nil
    #=> nil
    
    hash.values_at :test
    #=> [nil]
    

    在大多数情况下,默认值为nil的哈希#fetch可能是您想要的,但如果您愿意这样做,您肯定可以拯救KeyError或rescue nil(甚至rescue false),尽管真正意外异常的全能救援通常被认为是代码气味。