ruby語言中的string是mutable的,不像java、c#中的string是immutable的。比如
str1="abc"
str2="abc"
在java中,對于字面量的字元串,jvm内部維持一張表,是以如果在java中,str1和str2是同一個string對象。而在ruby中,str1和str2是完全不同的對象。同樣,在java中對于string對象的操作都将産生一個新的對象,而ruby則是操縱同一個對象,比如:
str="abc"
str.concat("cdf")
struct rstring {
struct rbasic basic;
long len;
char *ptr;
union {
long capa;
value shared;
} aux;
};
//ruby.h
顯然,len是string的長度;ptr是一個char類型的指針,指向實際的字元串;然後是一個聯合,這個稍後再說。如果你看看ruby.h可以發現,幾乎所有定義的對象結構都有一個struct rbasic。顯然,struct rbasic包含由所有對象結構體共享的一些重要資訊的。看看rbasic:
struct rbasic {
unsigned long flags;
value klass;
其中的flags是一個多用途的标記,大多數情況下用于記錄結構體的類型,ruby.h中預定義了一些列的宏,比如t_string(表示struct rstring),t_array(表示struct rarray)等。klass是一個value類型,value也是unsigned long,可以地将它當成指針(一個指針4位元組,綽綽有餘了),它指向的是一個ruby對象,這裡以後再深入。
那麼聯合aux中的capa和shared是幹什麼用的呢?因為ruby的string是可變的,可變意味着len可以改變,我們需要每次都根據len的變換來增減記憶體(使用c中的realloc()函數),這顯然是一個很大的開銷,解決辦法就是預留一定的空間,ptr指向的記憶體大小略大于len,這樣就不需要頻繁調用realloc了,aux.capa就是一個長度,包含額外的記憶體大小。那麼aux.shared是幹什麼的呢?這是一個value類型,說明它是指向某個對象。aux.shared其實是用于加快字元串的建立速度,在一個循環中:
#include<stdio.h>
static value t_test(value self)
{
value str;
str=rb_str_new2("str");
printf("before concat: str:%p, str.aux.shared:%p, str.ptr:%s"n",str,
(rstring(str)->aux).shared,rstring(str)->ptr);
rb_str_cat2(str,"ing");
printf("after concat: str:%p, str.aux.shared:%p, str.ptr:%s"n",
str,(rstring(str)->aux).shared,rstring(str)->ptr);
return self;
}
value ctest;
void init_string_hack(){
ctest=rb_define_class("test",rb_cobject);
rb_define_method(ctest,"test",t_test,0);
//string_hack.c