我正在研究Programming Ruby 1.9的例子。是否可以创建未暴露给Ruby的实例变量,仅在C中可见 - 例如,在t_init中初始化C结构并在t_add中使用它?
如果我在id_push下面声明结构或变量,它是类结构/变量,我需要实例。
是否可以在不使用Data_Wrap_Struct / Data_Get_Struct或rb_iv_set / rb_iv_get的情况下实现,因为Ruby中不需要实例变量,只能从C中看到它?
#include "ruby.h"
static ID id_push;
// how to define instance variables here?
static VALUE t_init(VALUE self) {
VALUE arr;
arr = rb_ary_new();
rb_iv_set(self, "@arr", arr);
return self;
}
static VALUE t_add(VALUE self, VALUE obj) {
VALUE arr;
arr = rb_iv_get(self, "@arr");
rb_funcall(arr, id_push, 1, obj);
return arr;
}
VALUE cTest;
void Init_my_test() {
cTest = rb_define_class("MyTest", rb_cObject);
rb_define_method(cTest, "initialize", t_init, 0);
rb_define_method(cTest, "add", t_add, 1); id_push = rb_intern("push");
}
答案 0 :(得分:3)
您正在寻找的C函数是 rb_ivar_set
和 rb_ivar_get
。
rb_ivar_set
有三个参数:
VALUE
- 类型的Ruby接收器对象ID
- 类型的ivar名称VALUE
- 类型的Ruby右侧对象。 rb_ivar_get
有两个参数:
VALUE
- 类型的Ruby接收器对象ID
- 类型的ivar名称 Ruby可以在内部存储具有多种ID
类型名称的实例变量。但是,从Ruby层可见的唯一变量名称是以@
开头的变量名,例如rb_intern("@foo")
。 退出@
会使实例变量无法从Ruby层访问,但允许您从C层存储和访问它。
以下是您实施此技术的代码示例。
#include "ruby.h"
static ID id_push;
static VALUE t_init(VALUE self) {
VALUE arr;
arr = rb_ary_new();
rb_ivar_set(self, rb_intern("arr"), arr); /* <-- */
return self;
}
static VALUE t_add(VALUE self, VALUE obj) {
VALUE arr;
arr = rb_ivar_get(self, rb_intern("arr")); /* <-- */
rb_funcall(arr, id_push, 1, obj);
return arr;
}
VALUE cTest;
void Init_my_test() {
cTest = rb_define_class("MyTest", rb_cObject);
rb_define_method(cTest, "initialize", t_init, 0);
rb_define_method(cTest, "add", t_add, 1); id_push = rb_intern("push");
}
测试出来!它应该像这样运行(我没有编译上面,可能有拼写错误):
require 'my_test'
class MyTest
def check
return @arr
end
end
t = MyTest.new
t.add(1) #=> [1]
t.check #=> nil
#check
方法寻找@arr
实例变量并空手而归。您的实例变量安全可靠,锁定在C层中!