我正在与什么应该是一个相当基本的迭代。我知道我可以用Ruby代码来完成它,但我已经在C扩展中工作,所以我宁愿用C代码保留这个函数 - 尤其是因为这个应该工作(单向或者其他方式) )没有问题。Ruby 1.9.1-p378 C扩展rb_block_call奇怪
问题在于rb_block_call。这里是README.EXT如何描述rb_block_call:
VALUE rb_block_call(VALUE recv, ID mid, int argc, VALUE * argv, VALUE (*func) (ANYARGS), VALUE data2)
呼吁对recv的方法,由符号 中期指定的 方法名,提供FUNC为块。 func将从yield 作为第一个参数获得值,data2作为 秒,argc/argv作为 第三个/第四个参数。
所以,我的理解(通过看红宝石内部验证),是接收函数应该是这样的:
VALUE function(VALUE rb_yield_value, VALUE data2, int argc, VALUE argv);
在这里,我们打我们的问题。在我的用例中(我将在下面介绍),rb_yield_value和data2按预期传递;另一方面,argc始终设置为1,argv [0]为rb_yield_value,argv [1]为false,argv [2]为rb_yield_value,argv [3]引发异常。
无论我为argc和argv传递什么,传递0和NULL结果相同,1和VALUE设置为Qtrue。所有与argc/argv保持一致的描述。
这里是我一起工作的代码:
VALUE rb_RPBDB_DatabaseObject_internal_cursorForCallingContext(VALUE rb_self) {
// when we are looking for the contextual iterator, we look up the current backtrace
// at each level of the backtrace we have an object and a method;
// if this object and method match keys present in self (tracking calling contexts for iteration in this iteration class) return cursor
VALUE rb_cursor_context_storage_hash = rb_RPBDB_DatabaseObject_internal_cursorContextStorageHash(rb_self);
VALUE rb_cursor = Qnil;
if (RHASH_SIZE(rb_cursor_context_storage_hash)) {
rb_block_call( rb_mKernel,
rb_intern("each_backtrace_frame"),
1,
& rb_cursor_context_storage_hash,
rb_RPBDB_DatabaseObject_internal_each_backtrace_frame,
rb_cursor);
}
return rb_cursor;
}
// walk up the stack one frame at a time
// for each frame we need to see if object/method are defined in our context storage hash
VALUE rb_RPBDB_DatabaseObject_internal_each_backtrace_frame( VALUE rb_this_backtrace_frame_hash,
VALUE rb_cursor_return,
int argc,
VALUE* args) {
// why are we getting 3 args when argc is 1 and none of the 3 match what was passed?
VALUE rb_cursor_context_storage_hash = args[ 0 ];
// each frame is identifiable as object/method
VALUE rb_this_frame_object = rb_hash_aref( rb_this_backtrace_frame_hash,
ID2SYM(rb_intern("object")));
VALUE rb_this_frame_method = rb_hash_aref( rb_this_backtrace_frame_hash,
ID2SYM(rb_intern("method")));
// we likely have "block in ..." for our method; we only want the "..."
rb_this_frame_method = ID2SYM(rb_to_id(rb_funcall( rb_obj_as_string(rb_this_frame_method),
rb_intern("gsub"),
2,
rb_str_new2("block in "),
rb_str_new2(""))));
VALUE rb_cursor_object_context_hash = rb_RPBDB_DatabaseObject_internal_cursorObjectContextStorageHash( rb_cursor_context_storage_hash,
rb_this_frame_object);
if (RHASH_SIZE(rb_cursor_object_context_hash)) {
rb_cursor_return = rb_hash_aref( rb_cursor_object_context_hash,
rb_this_frame_method);
}
return rb_cursor_return;
}
红宝石内部似乎并没有与ARGC/argv的rb_block_call的例子很多......最多一两个,我相信他们都只需在内部传递值而不是使用它们。
想法?
确定这实际上是有意义的审查。这确实是一个文档错误,因为文档说argc/argv将被传递给func(这是一个参数),而不是中间指定的Ruby方法。文档应为: 在recv上调用方法,方法名称由 符号指定,argc参数在argv中,提供func作为块。当func作为块被调用时,它将从yield作为第一个参数接收 值,并将data2作为第二个参数。 – Asher 2010-07-11 10:20:13
...和argc/argv作为第三/四个参数,作为块的生成值 – eregon 2010-07-11 10:40:15
argc/argv是内部的,在我们解决API时没有意义引用。 API文档的措辞不正确。文档引用的argc/argv引用了rb_block_call,而不是内部的rb_yield。该文件充其量是令人困惑的,但在我看来相当明显和简单的错误。它应该更新。 – Asher 2010-07-12 04:51:51