簡體   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