在 C 中扩展 ruby - 如何为函数指定默认参数值?
我正在尝试编写一个 ruby 的 C 扩展来生成一个类。我正在研究如何为类定义一些默认参数。例如,如果我在 ruby 中有这个类 declation:
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 使我相信我可以使用 argc 的值通过 rb_define_method 来完成此操作,但这还不太清楚。有什么想法吗?谢谢。
I'm trying to write a C extension to ruby that'll generate a class. I'm looking on how to define some default arguments to a class. For example, if I have this class decleration in ruby:
class MyClass
def initialize(name, age=10)
@name = name
@age = age
end
end
You can initialize it with mc = MyClass.new("blah")
, and the age parameter will be set internally. How do I do this in C? So far I got this, but this forces entering the other argument:
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);
}
I thought about checking the value of age
against Qnil
or using if ( TYPE(age) == T_UNDEF )
, but I just get segfaults from there. Reading through README.EXT
leads me to believe I can accomplish this through rb_define_method
using the value of argc
, but this wasn't too clear. Any ideas? Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你是对的 - 您可以使用
rb_define_method
和argc
的负值来做到这一点。通常
argc
指定方法接受的参数数量,但使用负值指定该方法接受可变数量的参数,Ruby 会将这些参数作为数组传入。有两种可能性。首先,如果您希望参数以 C 数组形式传递给方法,请使用
-1
。您的方法将具有类似VALUE func(int argc, VALUE *argv, VALUE obj)
的签名,其中argc
是参数数量,argv
是指向参数本身的指针,obj 是接收对象,即self
。然后,您可以根据需要模拟默认参数或任何您需要的内容来操作该数组,在您的情况下,它可能看起来像这样:另一种方法是将 Ruby 数组传递到您的方法中,您可以使用
- 指定该数组2
在您对rb_define_method
的调用中。在这种情况下,您的方法应具有类似VALUE func(VALUE obj, VALUE args)
的签名,其中obj
是接收对象 (self
),args
是一个包含参数的 Ruby 数组。在你的情况下,这可能看起来像这样:You're right - you can do this using
rb_define_method
and a negative value forargc
.Normally
argc
specifies the number of arguments your method accepts, but using a negative value specifies that the method accepts a variable number of arguments, which Ruby will pass in as an array.There are two possibilities. First, use
-1
if you want the arguments passed in to your method in a C array. Your method will have a signature likeVALUE func(int argc, VALUE *argv, VALUE obj)
whereargc
is the number of arguments,argv
is a pointer to the arguments themselves, and obj is the receiving object, i.e.self
. You can then manipulate this array as you need to mimic default arguments or whatever you need, in your case it might look something like this:The alternative is to have a Ruby array passed into your method, which you specify by using
-2
in your call torb_define_method
. In this case, your method should have a signature likeVALUE func(VALUE obj, VALUE args)
, whereobj
is the receiving object (self
), andargs
is a Ruby array containing the arguments. In your case this might look something like this:您确实需要使用
rb_define_method
的argc
。您应该将-1
作为argc
传递给rb_define_method
并使用rb_scan_args
处理可选参数。例如,matt 的示例可以简化为以下内容:用法
源自实用书架< /a>:
示例:
此外,在 Ruby 2 中,还有一个
:
标志用于命名参数和选项哈希。但是,我还没有弄清楚它是如何工作的。为什么?
使用
rb_scan_args
有很多优点:nil
(C中的Qnil
)来处理可选参数)。如果有人将nil
传递给可选参数之一(这种情况确实发生),这会产生副作用,防止您的扩展出现奇怪的行为。rb_error_arity
来引发 ArgumentError 采用标准格式(例如参数数量错误(2 表示1)
)。这里进一步阐述了
rb_scan_args
的优点:http://www.rb_scan_args。 oreillynet.com/ruby/blog/2007/04/c_extension_authors_use_rb_sca_1.htmlYou do need to use the
argc
ofrb_define_method
. You should pass-1
as theargc
torb_define_method
and userb_scan_args
to handle optional arguments. For example, matt's example could be simplified to the following:Usage
Derived from the Pragmatic Bookshelf:
Example:
Furthermore, in Ruby 2, there is also a
:
flag that is used for named arguments and the options hash. However, I have yet to figure out how it works.Why?
There are many advantages of using
rb_scan_args
:nil
(Qnil
in C). This has the side effect of preventing odd behaviour from your extension if someone passesnil
to one of the optional arguments, which does happen.rb_error_arity
to raise an ArgumentError in the standard format (ex.wrong number of arguments (2 for 1)
).The advantages of
rb_scan_args
are further elaborated here: http://www.oreillynet.com/ruby/blog/2007/04/c_extension_authors_use_rb_sca_1.html