繁体   English   中英

在C中扩展ruby - 如何指定默认参数值来运行?

[英]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_methodargc的负值来做到这一点。

通常, 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_methodargc 您应该将-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有许多优点:

  1. 它通过将它们分配为nil (C中的Qnil )来处理可选参数。 如果有人将nil传递给其中一个可选参数,这产生防止扩展程序奇怪行为的副作用。
  2. 它使用rb_error_arity以标准格式引发ArgumentError (例如, wrong number of arguments (2 for 1) )。
  3. 它通常更短。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM