3

我正在尝试将 if 条件转换为:

unless defined? SomeConstant
  # do some stuff
end

成为原生 C 扩展的一部分。有人知道如何defined?在 C API 中进行谓词检查吗?

编辑 | 我想我可以调用:

rb_funcall(rb_cObject, rb_intern("const_defined?"), 1, rb_intern("SomeConstant"))

尽管这在语义上显然略有不同。

4

1 回答 1

3

如果您跟踪 1.9.3 源代码,您会发现它defined?是在以下代码中实现的insns.def

DEFINE_INSN
defined
(rb_num_t op_type, VALUE obj, VALUE needstr)
/* ... */
    switch (type) {
    /* ... */
      case DEFINED_CONST:
        klass = v;
        if (vm_get_ev_const(th, GET_ISEQ(), klass, SYM2ID(obj), 1)) {
            expr_type = "constant";
        }
        break;

所以当你时defined? SomeConstant,你会通过那个大牌switch并最终跟注vm_get_ev_const。该函数定义在vm_insnhelper.c

static inline VALUE
vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq,
                VALUE orig_klass, ID id, int is_defined)

该功能恰好是静态的,因此您无法使用它。Looks likevm_get_ev_const是根据 and 定义的rb_const_definedrb_const_defined_from并且这两个都应该在您的 C 中可用,因此您可以尝试这些;但你必须klass为那些找到合适的。

或者你可以按照你的想法去做,然后使用Object.const_defined?. 这样做的一个问题是,它不会对诸如 之类的东西做正确的事情A::B,你必须为此说Object.const_defined? :A && A.const_defined? :B,因为这Object.const_defined? :'A::B'只会在你的脸上抛出一个异常。这里的一般解决方案需要迭代和类查找。但是,如果您正在查看的类都在顶级名称空间中,那么一个简单Object.const_defined?的就可以了。

于 2012-05-04T07:51:29.693 回答