我正在與什麼應該是一個相當基本的迭代。我知道我可以用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