基于瀏覽 Ruby API 源代碼Array#length,Range#begin我知道宏RARRAY_LEN和RANGE_BEG存在并用于實作相應的方法:
陣列#長度
static VALUE
rb_ary_length(VALUE ary)
{
long len = RARRAY_LEN(ary);
return LONG2NUM(len);
}
范圍#開始
static VALUE
range_begin(VALUE range)
{
return RANGE_BEG(range);
}
但是,雖然下面的代碼沒有問題,RARRAY_LEN但我無法開始RANGE_BEG作業:
測驗.c
#include "test.h"
VALUE rb_mTest = Qnil;
VALUE rb_cTest = Qnil;
VALUE super_initialize(VALUE self) {
return self;
}
VALUE array_len(VALUE self, VALUE ary) {
Check_Type(ary, T_ARRAY);
return LONG2NUM(RARRAY_LEN(ary)); // this works
}
VALUE range_begin(VALUE self, VALUE rng) {
if (rb_obj_is_kind_of(rng, rb_cRange)) {
// return RANGE_BEG(rng); // doesn't work
return rb_funcall(rng, rb_intern("begin"), 0); // this works
}
return Qnil;
}
void Init_test(void) {
rb_mTest = rb_define_module("RangeTest");
rb_cTest = rb_define_class_under(rb_mTest, "Tester", rb_cObject);
rb_define_method(rb_cTest, "initialize", super_initialize, 0);
rb_define_method(rb_cTest, "array_len", array_len, 1);
rb_define_method(rb_cTest, "begin_value", range_begin, 1);
}
測驗.h
#ifndef TEST_H
#define TEST_H 1
#include "ruby.h"
VALUE super_initialize(VALUE self);
void Init_test(void);
VALUE range_begin(VALUE self, VALUE rng);
VALUE array_len(VALUE self, VALUE ary);
#endif /* TEST_H */
當注釋行被激活時,編譯器會生成以下錯誤訊息:
error: implicit declaration of function 'RANGE_BEG' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
return RANGE_BEG(rng);
^
1 error generated.
這聽起來像是我錯過了一個include,但 1)不需要額外的包含RARRAY_LEN;2)包括range.h沒有改變任何東西;和 3)RANGE_BEG當我嘗試使用grep.
如您所見,我有一個解決方法rb_funcall,但想知道為什么在 Ruby 源代碼中找到的一個宏可以作業,而另一個不能。我查看的擴展檔案也暗示宏版本比函式呼叫版本更有效地進行資料訪問,因此使用宏會更好。
總而言之,我希望任何人都可以告訴我一個合適的咒語來讓編譯器訪問RANGE_BEG. 這發生在使用ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [arm64-darwin21]HomeBrew 安裝的 MacOS 12.4 (Monterey) 上,帶有CPPFLAGS=-I/opt/homebrew/opt/ruby/include和LDFLAGS=-L/opt/homebrew/opt/ruby/lib.
uj5u.com熱心網友回復:
無論出于何種原因,RANGE_XXX宏都不包含在 API 標頭中。它們僅在內部 Ruby 實作本身中定義和使用。似乎他們想讓這些方法保持私有,可能是為了確保在內部實作隨時間發生變化的情況下向后和向前兼容。
但是,您可以使用提供的方法通過 API 獲得幾乎相同的訪問權限rb_range_values:
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp);
你可以在這里查看它的實作,在這里你可以看到它實際上使用了那些內部宏。
要使用它,您只需定義回傳的變數,然后呼叫:
VALUE beg;
VALUE end;
int excl;
rb_range_values(range, &beg, &end, &excl);
盡管此方法比您需要的多一點,但它似乎仍然比使用 的版本更快funcall,但您需要進行基準測驗以確保。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/498155.html
