新手问题 Ruby 如何实现与 nil 的比较都返回 true (已解决)

thisiskun · 2015年09月16日 · 最后由 5swords 回复于 2015年09月30日 · 3794 次阅读

想自己实现一个小型的 DSL,绑定变量后,让表达式返回布尔值,比如:

a.foo > a.bar

如何让如上表达式在a.fooa.bar只要一个为 nil,就返回 true?

对于a.foo为 nil 的情况,我是这样实现的:

class NilClass
  methods = [:>, :<, :>=, :<=, :==, :!=]
  methods.each do |method|
    define_method method do |arg|
      return true
    end
  end
end

对于a.foo不为 nil(a.foo可以是任何数据类型),但是a.bar为 nil 的情况,如何实现呢?

最好不要改动原始的类,你可以用 NullObject 模式

直接改 Object 然后把比较函数给干了。 不过还是会被下级给重写掉吧?

感谢各位的回复:) @allenwei 使用 NullObject 模式的话,每个变量都要处理,会比较麻烦 @msg7086 直接改Object 的方式也想过,不过貌似太暴力了,不可取

目前想到的办法是在 Kernel 中定义bt, eq, not 之类的内核方法,在方法里面实现我要的逻辑,比如 bt(a.foo, a.bar) || eq(a.xixi, a.haha),这样也避免直接改动原始类了。

#4 楼 @msg7086 还可以接受啦,毕竟我只是一个使用 JRuby 的 Java 程序员啦😁

看出来了,楼主是来黑 Java 的 😄

哈哈,黑的漂亮。。。

自己的 DSL,似乎不用那么费事

def check(x, y)
  x.nil? || y.nil? || x > y
end

check(a.bar, b.bar)

不正规的说,用 rescue 来捉一下,出错的都是 true?

def  check_nil
  begin
    yield
  rescue NoMethodError, ArgumentError
    true
  end
end

check_nil { 1 > 2 }
check_nil { 2 > 1 }
check_nil { nil > 1 }
check_nil { 1 > nil }

不过这样好象更远了

@5swords 这样也是可以解决问题的,不过貌似有点啰嗦😅,每个都要被check_nil {} 包围着,条件一多,就会很长。 最终采用的该是@billy 的做法啦

#10 楼 @thisiskun 看元编程第 2 版 p36 的时候,想这个 refine 能不能拿来用。你看看。

module NilCompare
  [Object, Fixnum].each do |k|
    refine k do
      methods = [:>, :<, :>=, :<=, :==, :!=]
      methods.each do |method|
        define_method method do |arg|
          self.nil? || arg.nil? || self.send(method, arg)
        end
      end
    end
  end
end

module MyContext
  using NilCompare
  puts 1 > 2
  puts 2 > 1
  puts nil > 1
  puts 1 > nil
end

1 > nil
nil > 1
需要 登录 后方可回复, 如果你还没有账号请 注册新账号