我正在尝试转换if条件:
unless defined? SomeConstant
# do some stuff
end
成为本机C扩展的一部分。有人知道如何在C API中进行defined?
谓词检查吗?
编辑|我想我可以调用:
rb_funcall(rb_cObject, rb_intern("const_defined?"), 1, rb_intern("SomeConstant"))
虽然这在语义上略有不同。
答案 0 :(得分:3)
如果您浏览1.9.3来源,您会发现insns.def
中已实施defined?
:
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)
这个功能恰好是静态的,所以你无法得到它。看起来vm_get_ev_const
是根据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?
应该可以解决问题。