本文共 3564 字,大约阅读时间需要 11 分钟。
while true do # 无限重复 a = "str" # 以“str”为内容创建字符串,赋值给a a.concat("ing") # 为a所指向的对象添加“ing” p(a) # 显示“string” end 每次都重新创建一个"str"对象,内部就是重复创建一个char[],这是相当奢侈,aux.shared就是用于共享char[], 以字面量创建的字符串会共享一个char[],当要发生变化时,将字符串复制到一个非共享的内存中,变化针对这 个新拷贝进行,这就是所谓的“copy-on-write"技术。解释了String的内部构造,貌似还没有介绍String是怎么 实现mutable,我们写一个Ruby扩展测试下,我们想写这样一个Ruby类: class Test def test str="str" str.concat("ing") end end 对应的c语言代码就是:
rb_define_class函数定义了一个类Test,rb_define_method将t_test方法以test的名称添加到Test类。在
t_test中,通过rb_str_new2每次生成一个RString结构,然后通过rb_str_cat2将str与"ing"连接起来,添加 了一些打印用于跟踪。利用mkmf产生Makefile,写一个extconf.rb require 'mkmf' create_makefile("string_hack"); 执行ruby extconf.rb,将产生一个Makefile,执行make,生成一个string_hack.so的链接库。扩展写完了,通过 ruby调用: require 'string_hack" t=Test.new (1..3).each{|i| t.test} 输出: before concat: str:0x40098a40, str.aux.shared:0x3, str.ptr:str after concat: str:0x40098a40, str.aux.shared:0x8, str.ptr:string before concat: str:0x40098a2c, str.aux.shared:0x3, str.ptr:str after concat: str:0x40098a2c, str.aux.shared:0x8, str.ptr:string before concat: str:0x40098a18, str.aux.shared:0x3, str.ptr:str after concat: str:0x40098a18, str.aux.shared:0x8, str.ptr:string 从结果可以看出,在str concat之前之后,str指向的位置没有改变,改变的仅仅是str中ptr指向的字符串的值 ,看看rb_str_cat2函数的实现就一目了然了: VALUE rb_str_cat(str, ptr, len) VALUE str; const char *ptr; long len; { if (len < 0) { rb_raise(rb_eArgError, "negative string size (or size too big)"); } if (FL_TEST(str, STR_ASSOC)) { rb_str_modify(str); REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+len); memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); RSTRING(str)->len += len; RSTRING(str)->ptr[RSTRING(str)->len] = '"0'; /* sentinel */ return str; } return rb_str_buf_cat(str, ptr, len); } VALUE rb_str_cat2(str, ptr) VALUE str; const char *ptr; { return rb_str_cat(str, ptr, strlen(ptr)); } //string.c文章转自庄周梦蝶 ,原文发布时间2007-09-12
转载地址:http://bdesa.baihongyu.com/