麻烦否定了Ruby中的`is_a?`

时间:2013-11-03 11:21:59

标签: ruby

class C
   attr_accessor :v
   def initialize(arg)
     @v = arg
   end
   def meth(arg=nil)
     return arg.meth unless (arg.nil?) && !(arg.is_a? self.class)
     @v
   end
end

meth中,如果arg不是nil且arg.meth,我想arg.is_a?C。否则返回@v。但我想这部分!(arg.is_a? self.class)是不正确的。无法弄清楚什么是错的。

x = C.new("first")
y = C.new("second")

x.meth #=> "first"
x.meth(y) #=> "second"
x.meth(10) #=> I was expecting 'first'

But I get NoMethodError: undefined method `meth' for 10:Fixnum

我不想否定arg.nil?我希望实现arg.is_not_a?

更新:看起来我的问题令人困惑。我想在这里澄清一下

if the argument passed to meth is not nil and is of type C then 
  call arg.meth 
else 
  return @v
end

3 个答案:

答案 0 :(得分:1)

10.nil?为false,因此(arg.nil?) && !(arg.is_a? self.class)为false,并且考虑到unless的工作方式,您的方法将尝试调用10.meth

将该行替换为:

return arg.meth if !arg.nil? && (arg.is_a? self.class)

return arg.meth unless arg.nil? || !(arg.is_a? self.class)

编辑:由于arg.is_a? self.class暗示!arg.nil?,上述内容是多余的,应该只是:

return arg.meth if arg.is_a? self.class

或者,如果你真的想要使用,除非:

return arg.meth unless !(arg.is_a? self.class)

显式返回不是惯用的Ruby,所以像这样的东西可能是理想的

def meth(arg=nil)
  arg.is_a?(self.class) ? arg.meth : @v
end

答案 1 :(得分:0)

如果(arg.nil?) && !(arg.is_a? self.class)arg 并且 nil不是arg的(子)实例,则条件self.class将为真。您在unless中使用了这一条件,因此一切都相反:“arg nil”变为“arg不是nil”,“{{ 1}}不是arg的(子)实例“变成”self.classarg的(子)实例“,最重要的是 - ”和“变成”或“ - 这就是您的问题:如果self.class不是arg.meth argnil的(子)实例,则会调用arg - 但是如果两个条件都为真,你只希望它发生。

所以 - 将self.class更改为&&,或将||更改为unless(并相应地重写条件)

答案 2 :(得分:0)

正如你所说 - meth我希望arg.meth如果arg不是nilarg.is_a C。否则返回{{1} }。

这可以通过在@v上简单地调用方法#instance_of?来处理。您无需明确检查arg对象。仅当nil是类if的实例时,true语句才会被评估为argCnil都不是类10的实例,所以C不会发生,因为arg.meth子句将被评估为if。这实际上满足了您的需求。false子句中会发生arg.meth,而if将成为类arg的实例。这就是c这一行中发生的情况。

以下是您要获取的代码:

x.meth(y)