【问题标题】:How to pass keywords to a Ruby method from a C extension?如何将关键字从 C 扩展传递给 Ruby 方法?
【发布时间】:2016-10-29 02:43:57
【问题描述】:

我正在为 Ruby 开发一个 C 扩展,我想调用一个需要关键字参数的方法,如下所示:

class Word 
  def initialize(line:, col:, value:)
  end 
end 

在 C 语言中,我熟悉通过 rb_funcallrb_funcallv 调用 Ruby 方法,但我不知道如何传递关键字参数!

以下是我尝试过的一些事情:

使用rb_funcall 传递一个哈希作为最后一个位置参数:

VALUE kwargs = rb_hash_new();
rb_hash_aset(kwargs, rb_intern("name"), rb_str_new2(name));
// ... 
rb_funcall(Word_Class, rb_intern("new"), 1, kwargs);
// result: ArgumentError: wrong number of arguments (given 1, expected 0)

将其作为argv 数组的最后一个成员传递给rb_funcallv

// initialize `kwargs` as above
VALUE argv = rb_ary_new();
rb_ary_push(argv, kwargs);
rb_funcallv(Word_Class, rb_intern("new"), 1, &argv);
// result: ArgumentError: wrong number of arguments (given 1, expected 0)

0 传递为argc,即使argv 的长度是1

// initialize `argv` as above
rb_funcallv(Word_Class, rb_intern("new"), 0, &argv);
// ArgumentError: missing keywords: line, col, value

有可能吗?它是如何完成的?还有什么我可以尝试的吗?

【问题讨论】:

  • 认为你应该能够只传递一个哈希(rb_hash_new 用于创建它,rb_hash_aset 用于设置值)。让我知道这是否有效,然后我可以将其转化为答案。
  • 感谢您的建议!我用我尝试过的一些东西更新了这个问题......还有其他方法可以尝试将哈希作为关键字传递吗?
  • 您第一次尝试时就在正确的行上(将哈希作为最后一个参数传递),但键必须是符号,而不是 ID。试试ID2SYM(rb_intern("name")) 而不仅仅是rb_intern("name")。不知道有没有办法一步一步将C中的char *直接转成ruby符号,看来需要先创建一个ID再转成符号。
  • @matt 它有效!您能否将该建议添加为“答案”,以便我接受它并为您提供神奇的堆栈溢出点?
  • 我认为@MichaelKohl 优先获得这些积分。

标签: ruby ruby-c-extension keyword-argument


【解决方案1】:

你可以传入一个哈希值。请注意,要创建符号键,您需要调用 ID2SYM(rb_intern(char*)) 形式,因为 rb_intern 返回一个 ID,而 ID2SYM 会变成一个实际的 Ruby 符号。

VALUE kwargs = rb_hash_new();
rb_hash_aset(kwargs, ID2SYM(rb_intern("name")), rb_str_new2(name));
// ... 
rb_funcall(Word_Class, ID2SYM(rb_intern("new")), 1, kwargs);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 2014-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多