为什么`a.is_a?数组 && !a.empty?` 引发 NoMethodError?
Why does `a.is_a? Array && !a.empty?` raise NoMethodError?
我是一名 Python 开发人员,我刚刚开始学习 Rails,所以这可能是一个菜鸟问题。我在我的代码中发现了一些令人惊讶的行为:
<!-- render flash message array if set -->
<% if flash[:notice].is_a? Array && !flash[:notice].empty? %>
这会导致以下错误:undefined method `empty?' for nil:NilClass
似乎 Ruby 不应该在该子句的第二部分调用 .empty?
。我确认短路评估在其他情况下有效:
# this is more what I expected
[3] pry(main)> a = nil
=> nil
[5] pry(main)> !a.nil? && a.empty?
=> false
...
[6] pry(main)> a = 1
=> 1
[7] pry(main)> !a.nil? && a.empty?
NoMethodError: undefined method `empty?' for 1:Integer
from (pry):7:in `__pry__'
有人知道为什么会发生这种行为吗?似乎只在我使用 is_a?
而不是其他运算符时触发。
因为NilClass
没有回复empty
:
nil.class #=> NilClass
nil.respond_to? :empty?
#=> false
当它响应 is_a?
时:
nil.respond_to? :is_a?
#=> true
显示所有方法nil
响应:
nil.methods
#=> [:&, :inspect, :to_a, :to_s, :===, :to_f, :to_i, :=~, :to_h, :nil?, :to_r, :rationalize, :|, :to_c, :^, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :protected_methods, :instance_variables, :instance_variable_get, :public_methods, :private_methods, :method, :public_method, :public_send, :singleton_method, :define_singleton_method, :extend, :to_enum, :enum_for, :<=>, :!~, :eql?, :respond_to?, :freeze, :object_id, :send, :display, :hash, :class, :singleton_class, :clone, :dup, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :equal?, :!, :==, :instance_exec, :!=, :instance_eval, :__id__, :__send__]
如果您通过首先检查键 :notice
的值是否存在来修复,如本例所示:https://api.rubyonrails.org/classes/ActionDispatch/Flash.html,则会引发语法错误,指出缺少括号:
flash[:notice] && flash[:notice].is_a? Array && flash[:notice].empty?
# syntax error, unexpected tCONSTANT, expecting end-of-input
# ...] && flash[:notice].is_a? Array && flash[:notice].empty?
# ^~~~~
发生这种情况是因为您使用的是 space 而不是 is_a?
函数参数的方括号,因此 rails 试图将整个参数作为参数发送。试试这个
<% if flash[:notice].is_a?(Array) && !flash[:notice].empty? %>
解释:
当你写 flash[:notice].is_a? Array && !flash[:notice].empty?
rails 时将其解释为 flash[:notice].is_a?(Array && !flash[:notice].empty?)
所以 Array
被评估为 true
并且 !flash[:notice].empty?
被评估从而提高异常。
我是一名 Python 开发人员,我刚刚开始学习 Rails,所以这可能是一个菜鸟问题。我在我的代码中发现了一些令人惊讶的行为:
<!-- render flash message array if set -->
<% if flash[:notice].is_a? Array && !flash[:notice].empty? %>
这会导致以下错误:undefined method `empty?' for nil:NilClass
似乎 Ruby 不应该在该子句的第二部分调用 .empty?
。我确认短路评估在其他情况下有效:
# this is more what I expected
[3] pry(main)> a = nil
=> nil
[5] pry(main)> !a.nil? && a.empty?
=> false
...
[6] pry(main)> a = 1
=> 1
[7] pry(main)> !a.nil? && a.empty?
NoMethodError: undefined method `empty?' for 1:Integer
from (pry):7:in `__pry__'
有人知道为什么会发生这种行为吗?似乎只在我使用 is_a?
而不是其他运算符时触发。
因为NilClass
没有回复empty
:
nil.class #=> NilClass
nil.respond_to? :empty?
#=> false
当它响应 is_a?
时:
nil.respond_to? :is_a?
#=> true
显示所有方法nil
响应:
nil.methods
#=> [:&, :inspect, :to_a, :to_s, :===, :to_f, :to_i, :=~, :to_h, :nil?, :to_r, :rationalize, :|, :to_c, :^, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :protected_methods, :instance_variables, :instance_variable_get, :public_methods, :private_methods, :method, :public_method, :public_send, :singleton_method, :define_singleton_method, :extend, :to_enum, :enum_for, :<=>, :!~, :eql?, :respond_to?, :freeze, :object_id, :send, :display, :hash, :class, :singleton_class, :clone, :dup, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :equal?, :!, :==, :instance_exec, :!=, :instance_eval, :__id__, :__send__]
如果您通过首先检查键
:notice
的值是否存在来修复,如本例所示:https://api.rubyonrails.org/classes/ActionDispatch/Flash.html,则会引发语法错误,指出缺少括号:
flash[:notice] && flash[:notice].is_a? Array && flash[:notice].empty?
# syntax error, unexpected tCONSTANT, expecting end-of-input
# ...] && flash[:notice].is_a? Array && flash[:notice].empty?
# ^~~~~
发生这种情况是因为您使用的是 space 而不是 is_a?
函数参数的方括号,因此 rails 试图将整个参数作为参数发送。试试这个
<% if flash[:notice].is_a?(Array) && !flash[:notice].empty? %>
解释:
当你写 flash[:notice].is_a? Array && !flash[:notice].empty?
rails 时将其解释为 flash[:notice].is_a?(Array && !flash[:notice].empty?)
所以 Array
被评估为 true
并且 !flash[:notice].empty?
被评估从而提高异常。