2014-03-02 71 views
3

我正在研究Programming Ruby 1.9的示例。是否有可能創建不暴露給Ruby的實例變量,僅在C中可見 - 例如初始化t_init中的C結構並在t_add中使用它?如何在C擴展中的Ruby層隱藏實例變量?

如果我在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"); 
} 

回答

3

你正在尋找的C函數是rb_ivar_setrb_ivar_get

rb_ivar_set有三個參數:

  1. VALUE型紅寶石接收器對象
  2. ID型的ivar名稱分配
  3. VALUE型紅寶石右手側對象。

rb_ivar_get有兩個參數:

  1. VALUE型紅寶石接收對象
  2. ID型伊娃名稱檢索

紅寶石可以與多種內部存儲實例變量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層!

+1

這太可怕了:-)它可能會工作,但你確定GC會用這些部分可訪問的東西做正確的事情嗎?任何備受推崇的擴展庫實際上是否使用此技術作爲快捷方式(以隱藏由C添加的實例變量)? –

+1

好的,發現'rb_iv_set'和'rb_ivar_set'之間的區別,現在有意義(和+1),最初我以爲你建議在沒有'@'的情況下使用'rb_iv_set'。 。 。 –

+0

它的工作原理是,我現在可以將C結構保存爲類實例變量,僅在C中可見,並且在shell嘗試顯示它們並且conf.echo處於活動狀態時,irb中不會出現段錯誤。 Ruby垃圾收集器也會清理這些變量,或者? – bsrdjan