我正在尝试将 if 条件转换为:
unless defined? SomeConstant
# do some stuff
end
成为原生 C 扩展的一部分。有人知道如何defined?
在 C API 中进行谓词检查吗?
编辑 | 我想我可以调用:
rb_funcall(rb_cObject, rb_intern("const_defined?"), 1, rb_intern("SomeConstant"))
尽管这在语义上显然略有不同。
我正在尝试将 if 条件转换为:
unless defined? SomeConstant
# do some stuff
end
成为原生 C 扩展的一部分。有人知道如何defined?
在 C API 中进行谓词检查吗?
编辑 | 我想我可以调用:
rb_funcall(rb_cObject, rb_intern("const_defined?"), 1, rb_intern("SomeConstant"))
尽管这在语义上显然略有不同。
如果您跟踪 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_defined
,rb_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?
的就可以了。