为何Ruby的if...and语句中添加respond_to?(:uid)可避免NoMethodError?
为什么添加
entry.respond_to?(:uid)后不再抛出NoMethodError? 这是因为Ruby的逻辑与运算符(and/&&)支持短路求值——当第一个条件判断为false时,第二个条件会被直接跳过,不会执行。
具体分析:
原代码的问题:
当LDAP返回的entry没有uid属性时,直接执行entry.uid[0].to_s会触发NoMethodError,因为entry对象根本没有uid这个方法。原代码片段:
filter_person = Net::LDAP::Filter.eq("objectClass", "person") treebase = "ou=people,dc=rocketfuel,dc=com" ldap.search(:base => treebase, :filter => filter_person, :scope => Net::LDAP::SearchScope_SingleLevel, :attributes => ['uid', 'sshpublickey']) do |entry| if users_uids.include?(entry.uid[0].to_s) p entry.uid[0].to_s end end抛出异常:
NoMethodError: undefined method `uid' for #<Net::LDAP::Entry:0x00000000074bf558>修改后代码的逻辑:
你添加的entry.respond_to?(:uid)会先判断entry是否有uid方法:- 如果返回
true(存在uid方法),才会继续执行后面的users_uids.include?(entry.uid[0].to_s); - 如果返回
false(不存在uid方法),and后面的代码会被直接跳过,不会去调用entry.uid,自然不会抛出异常。
修改后的代码片段:
if entry.respond_to?(:uid) and users_uids.include?(entry.uid[0].to_s) p entry.uid[0].to_s end- 如果返回
补充:
Ruby里&&和and都是短路与,区别仅在于运算符优先级,这里用两者效果一致。另外,也可以用Ruby的安全导航运算符&.简化写法,比如:
if users_uids.include?(entry.uid&.[](0)&.to_s) p entry.uid&.[](0)&.to_s end
不过本质上和你用respond_to?加短路求值的逻辑是一样的,都是避免在不存在方法时调用它。
内容的提问来源于stack exchange,提问作者Maxim Maximov
相关产品推荐
相关产品推荐

