Symbols(mruby 符号)

译者Lanza Schneider

(译者注:这章的符号就是 Ruby 中的 Symbol 对象,顾名思义,它是一个充当符号的物件,用于变量名、方法名、常量名等各种需要标识符的地方)

mruby C 源代码中的符号由mrb_sym表示,它是uint32_t的别名。 其中,低30位用作符号,而高2位用作flags,例如class.c中出现的struct mt_elem

struct mt_elem {
  union mt_ptr ptr;
  size_t func_p:1;
  size_t noarg_p:1;
  mrb_sym key:sizeof(mrb_sym)*8-2;
};

C API

我们为符号提供了如下的 C API。

生成符号

mrb_sym mrb_intern(mrb_state*,const char*,size_t)

用字符串获取一个对应的符号。

mrb_sym mrb_intern_check_cstr(mrb_state*,const char*)

用一个以 NULL 结尾的 C 字符串获取一个对应的符号。

mrb_sym mrb_intern_str(mrb_state*,mrb_value)

用一个 Ruby 字符串对象获取一个对应的符号。

mrb_intern_lit(mrb_state*,const char*)

从一个 C 字符串字面量中获取一个对应的符号,第二个参数一定要是 C 字符串字面量才行,否则就会产生一个编译错误。也因为是字面量,所以这个函数并不会拷贝这个 C 字符串。

mrb_sym mrb_intern_check(mrb_state*,const char*,size_t)

用一个字符串获取一个对应的符号,如果该符号还没有被注册,那就返回0。 这个函数还有两个变体,一个是 mrb_intern_check_str()用于 Ruby 字符串对象; 还有一个mrb_intern_check_cstr()用于 C 字符串。

const char *mrb_sym_name(mrb_state*,mrb_sym)

获取一个符号的 C 字符串表示。

const char *mrb_sym_name_len(mrb_state*,mrb_sym,mrb_int*)

获取一个符号的字符串表示以及其长度。

预分配符号(mruby 3.x 特性)

为了节省 RAM,mruby 可以在编译时就分配一些符号,你可以通过包含mruby/presym.h并使用如下的宏来获得预分配的符号。

  • MRB_SYM(xor) //=> xor (和名称完全一致的符号)
  • MRB_SYM_B(xor) //=> xor! (带叹号,用于方法名)
  • MRB_SYM_Q(xor) //=> xor? (带问号,用于方法名)
  • MRB_SYM_E(xor) //=> xor= (带等号,用于方法名)
  • MRB_CVSYM(xor) //=> @@xor (带两个@前缀,用于类变量)
  • MRB_IVSYM(xor) //=> @xor (带一个@前缀,用于实例变量)
  • MRB_OPSYM(xor) //=> ^ (由名称转换而来的操作符)

对于 MRB_OPSYM(), 请指定与运算符对应的名称 (参见 lib/mruby/presym.rb 中的 MRuby::Presym::OPERATORS 来获取名称)。 除此之外,只描述符号名称,不要包括前缀以及后缀的标点符号。

这些宏在编译时被转换成静态的符号 ID ,除非预分配符号被conf.disable_presym禁用。在这种情况下,这些宏会被扩展成mrb_intern_lit调用,因此 mruby 的状态参数是必须的,而上面的宏假定这个状态参数在当前上下文叫作mrb,如果不是的话,你就要使用后缀为_2的宏,如MRB_SYM_2来传入mrb_state*参数。

禁用预分配符号

你可以通过在配置文件中调用conf.disable_presym来禁用预分配符号特性。