我用Ruby的C API创建了一些类。我想创建一个函数,其行为将根据Ruby对象的类而改变。
我尝试使用Ruby中的is_a?
,但是,我不认为这是做到这一点的好方法。我检查了“Creating Extension Libraries for Ruby”但没有成功。检查类的唯一直接方法是使用默认类型。
我的班级“Klass”已经创建:
VALUE rb_cKlass = rb_define_class("Klass", rb_cObject);
我想如何检查班级是否合适:
VALUE my_function(VALUE self, VALUE my_argument) {
if(rb_check_class(my_argument), rb_cKlass)) {
// do something if my_argument is an instance of Klass
} else {
return Qnil;
}
}
有办法做到这一点吗?
答案 0 :(得分:2)
每个ruby对象在内部由RObject
struct表示(为了将来的读者,我将在这里复制源代码):
struct RObject {
struct RBasic basic;
union {
struct {
uint32_t numiv;
VALUE *ivptr;
void *iv_index_tbl; /* shortcut for RCLASS_IV_INDEX_TBL(rb_obj_class(obj)) */
} heap;
VALUE ary[ROBJECT_EMBED_LEN_MAX];
} as;
};
第一个成员RBasic
定义了类:
struct RBasic {
VALUE flags;
const VALUE klass;
}
要访问任何内容的RBasic
元数据,可以使用RBASIC
宏:
RBASIC(my_argument)
要直接获取课程,可以使用RBASIC_CLASS
宏:
RBASIC_CLASS(my_argument)
答案 1 :(得分:0)
我最近遇到了这个问题,并使用了RBASIC_CLASS
宏,但是由于某些无法解释的原因,在某些情况下出现了段错误。
扫描ruby.h
后,我发现了CLASS_OF
宏,该宏将给定对象的类返回为VALUE
。
VALUE obj = INT2NUM(10);
VALUE klass = CLASS_OF(obj); // rb_cInteger
使用Ruby 2.5
答案 2 :(得分:0)
如果你想接近 is_a?
Ruby 风格(即检查是否有任何祖先是预期的类),你可以直接使用 is_a?
, {{1} 的 C 实现}:
rb_obj_is_kind_of
并且由于 rb_obj_is_kind_of(my_argument, rb_cKlass) // Qtrue OR Qfalse
,您可以使用该方法作为条件:
Qfalse == 0
要找到此方法,只需选中 Object#is_a?
documentation 并单击以切换源代码,如果它是 C 函数,您将看到 C 实现(因此这适用于大多数标准库)。