![](/img/trans.png)
[英]Is it possible to create a default value for an argument in a function with C?
[英]Extending ruby in C - how to specify default argument values to function?
我正在嘗試為ruby寫一個C擴展,它將生成一個類。 我正在研究如何為類定義一些默認參數。 例如,如果我在ruby中有這個類的decleration:
class MyClass
def initialize(name, age=10)
@name = name
@age = age
end
end
您可以使用mc = MyClass.new("blah")
對其進行初始化,並在內部設置age參數。 我怎么用C做這個? 到目前為止,我得到了這個,但這迫使進入另一個論點:
require "ruby.h"
static VALUE my_init(VALUE self, VALUE name, VALUE age)
{
rb_iv_set(self, "@name", name);
rb_iv_set(self, "@age", age);
return self;
}
VALUE cMyClass;
void Init_MyClass()
{
// create a ruby class instance
cMyClass = rb_define_class("MyClass", rb_cObject);
// connect the instance methods to the object
rb_define_method(cMyClass, "initialize", my_init, 2);
}
我考慮過針對Qnil
檢查age
的值或使用if ( TYPE(age) == T_UNDEF )
,但我只是從那里得到段錯誤。 閱讀README.EXT
讓我相信我可以通過rb_define_method
使用argc
的值來實現這一目標,但這不太清楚。 有任何想法嗎? 謝謝。
你是對的 - 你可以使用rb_define_method
和argc
的負值來做到這一點。
通常, argc
指定方法接受的參數數量,但使用負值指定方法接受可變數量的參數,Ruby將作為數組傳入。
有兩種可能性。 首先,如果希望將參數傳入C方法中的方法,請使用-1
。 你的方法將有一個像VALUE func(int argc, VALUE *argv, VALUE obj)
這樣的簽名VALUE func(int argc, VALUE *argv, VALUE obj)
其中argc
是參數的數量, argv
是參數本身的指針,而obj是接收對象,即self
。 然后你可以操作這個數組,因為你需要模仿默認的參數或你需要的任何東西,在你的情況下,它可能看起來像這樣:
static VALUE my_init(int argc, VALUE* argv, VALUE self) {
VALUE age;
if (argc > 2 || argc == 0) { // there should only be 1 or 2 arguments
rb_raise(rb_eArgError, "wrong number of arguments");
}
rb_iv_set(self, "@name", argv[0]);
if (argc == 2) { // if age has been included in the call...
age = argv[1]; // then use the value passed in...
} else { // otherwise...
age = INT2NUM(10); // use the default value
}
rb_iv_set(self, "@age", age);
return self;
}
另一種方法是將一個Ruby數組傳遞給您的方法,您可以在調用rb_define_method
使用-2
指定。 在這種情況下,您的方法應該有一個簽名,如VALUE func(VALUE obj, VALUE args)
,其中obj
是接收對象( self
), args
是包含參數的Ruby數組。 在您的情況下,這可能看起來像這樣:
static VALUE my_init(VALUE self, VALUE args) {
VALUE age;
long len = RARRAY_LEN(args);
if (len > 2 || len == 0) {
rb_raise(rb_eArgError, "wrong number of arguments");
}
rb_iv_set(self, "@name", rb_ary_entry(args, 0));
if (len == 2) {
age = rb_ary_entry(args, 1);
} else {
age = INT2NUM(10);
}
rb_iv_set(self, "@age", age);
return self;
}
您需要使用rb_define_method
的argc
。 您應該將-1
作為argc
傳遞給rb_define_method
並使用rb_scan_args
來處理可選參數。 例如,matt的示例可以簡化為以下內容:
static VALUE my_init(int argc, VALUE* argv, VALUE self) {
VALUE name, age;
rb_scan_args(argc, argv, "11", &name, &age); // informs ruby that the method takes 1 mandatory and 1 optional argument,
// the values of which are stored in name and age.
if (NIL_P(age)) // if no age was given...
age = INT2NUM(10); // use the default value
rb_iv_set(self, "@age", age);
rb_iv_set(self, "@name", name);
return self;
}
用法
源自實用書架 :
int rb_scan_args (int argcount, VALUE *argv, char *fmt, ...
Scans the argument list and assigns to variables similar to scanf:
fmt A string containing zero, one, or two digits followed by some flag characters.
The first digit indicates the count of mandatory arguments; the second is the count of optional arguments.
A * means to pack the rest of the arguments into a Ruby array.
A & means that an attached code block will be taken and assigned to the given variable
(if no code block was given, Qnil will be assigned).
After the fmt string, pointers to VALUE are given (as with scanf) to which the arguments are assigned.
例:
VALUE name, one, two, rest;
rb_scan_args(argc, argv, "12", &name, &one, &two);
rb_scan_args(argc, argv, "1*", &name, &rest);
此外,在Ruby 2中,還有一個:
標志,用於命名參數和選項哈希。 但是,我還沒弄清楚它是如何工作的。
為什么?
使用rb_scan_args
有許多優點:
nil
(C中的Qnil
)來處理可選參數。 如果有人將nil
傳遞給其中一個可選參數,這會產生防止擴展程序奇怪行為的副作用。 rb_error_arity
以標准格式引發ArgumentError (例如, wrong number of arguments (2 for 1)
)。 rb_scan_args
的優點在rb_scan_args
進一步闡述: http : //www.oreillynet.com/ruby/blog/2007/04/c_extension_authors_use_rb_sca_1.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.