VALUE是Ruby的C实现中用来"
指向/引用/代表"所有Ruby对象的"
指针"的统一的类型
通过统一类型,可以获得类似"多态"的好处,ruby实现起来就更为简洁(代码方面).
然后, 同样是出于实现的考虑(性能方面), VALUE并不全是指针:
1. 小的整数
2. 符号
3. true
4. false
5. nil
6. Qundef
以上六位就是所谓的"内嵌对象"(VALUE并不是内存地址,其代表的对象是内嵌在VALUE的数值中).
小整数的内嵌规则是:
#define INT2FIX(i) ((VALUE)(((long)(i))<<1 | FIXNUM_FLAG))
#define FIXNUM_FLAG 0x01
数值乘以2再加1(奇数).
符号的内嵌规则是:
#define SYMBOL_FLAG 0x0e
#define ID2SYM(x) ((VALUE)(((long)(x))<<8|SYMBOL_FLAG))
数值乘以256再加14(不能被4整除的偶数)
看到这里,大家可能会疑惑,小整数的数值是本身,但符号(Symbol)的数值又是什么呢?
简单来说,每个ruby进程中维护了一个字符串和数值一一对应的hash表,
因此就可以使用数值来代表(Identify)字符串所表示的"名字", 减少了内存和字符串比较的开销.
static NODE*
search_method(klass, id, origin)
VALUE klass, *origin;
ID id;
{
NODE *body;
if (!klass) return 0;
while (!st_lookup(RCLASS(klass)->m_tbl, id, &body)) {
klass = RCLASS(klass)->super;
if (!klass) return 0;
}
if (origin) *origin = klass;
return body;
}
例如这个search_method就是在klass类中搜索名称的ID为id的方法, 并将方法的"出处"(定义方法的类)保存在orgin中.
Ruby为"数值"的"特殊使用"(用做'名字'的ID)单独创建了一个类型:符号(Symbol).
3-6的内嵌规则是:
#define Qfalse 0 /* Ruby's false */
#define Qtrue 2 /* Ruby's true */
#define Qnil 4 /* Ruby's nil */
#define Qundef 6 /* undefined value for placeholder */
除了内嵌对象外, VALUE的值便是Ruby对象对应的C结构体的内存地址.
C结构体的内存通常不是从第一个块(0-?)开始分配的,因此不会和Qfalse,Qnil冲突.
且所有Ruby对象的C结构体的共同特征是,其内存地址一定是4的倍数(还记得C中Struct对齐么?).
因此,仅凭VALUE的数值就可以区分它是小整数,符号,Q值,还是内存地址(有
例外!).
switch (TYPE(obj)) {
/* (A) */
case T_OBJECT:
case T_CLASS:
case T_MODULE:
if (ROBJECT(obj)->iv_tbl &&
st_lookup(ROBJECT(obj)->iv_tbl, id, &val))
return val;
break;
/* (B) */
default:
if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
return generic_ivar_get(obj, id);
break;
}
看到代码中的TYPE宏么, 就是根据VALUE的数值返回obj可能指向的结构体的类型.
例如,一个RString类型的结构体实例的TYPE就是T_STRING. 那么TYPE(2)会返回T_FIXNUM么?
错! 应返回T_TRUE?(如果有...), 而TYPE(3)则返回T_FIXNUM.
TYPE宏可以区分内嵌对象和对象,那么,它是如何区分不同的对象的呢?此时,VALUE的值都是内存地址, 不同的是它所指向的结构体.正如你想的那样, TYPE宏在运行时区分结构体类型的能力正是来源于结构体本身,换句话说,结构体存储了自身的类型信息.关于这些结构体,详见 Ruby的
对象类.
- 大小: 6.5 KB
分享到:
相关推荐
在JavaScript编程中,获取对象和数组的属性键值(key)和对应值(value)是一项基本操作。本文将详细介绍如何实现这一功能,并提供相应的代码示例。 首先,我们需要理解JavaScript中的对象和数组。对象是一种键值对...
在本文中,我们将深入探讨如何在SpringBoot中实现接口的加密解密统一处理,以及如何通过自定义注解来灵活控制加密解密的执行。 首先,我们创建两个自定义注解,`DecryptRequest`和`EncryptResponse`,用于标识哪些...
递归遍历对象时,我们通常需要处理对象的嵌套层级,并且每个层级都可能包含不同的数据类型。为了能够全面地获取到所有的值,递归函数需要能够识别和处理各种不同的数据类型,包括嵌套的对象、数组、字符串、数字等。...
getKeyValue(对象: JSObject ) JSObject可以是具有一个或多个属性的对象 返回 一个属性应该返回一个带有{key, value}的js 对象 多个属性应该返回一个包含[{key, value}, {key, value}]的数组 undefined以防传递...
java使用fastJson处理复杂Json字符串,直接获取key对应的value值
例:获取ul中li的value值 首先,在html中我们要为每个li设置value值 代码如下: <ul> <li value=”你好”></li> <li value=”hello”></li> <li value=”></li> </ul> 再通过jquery根据点击事件获取对应的value 代码...
4. **事件处理**:在Unity中,你可以通过两种方式处理OnValueChanged事件:一是使用Unity的EventSystem和IPointerClickHandler接口,另一种是使用C#脚本直接挂接OnValueChanged事件。后一种方法通常更直观,只需在...
在Python中,面向对象编程是其核心特性之一,使得Python成为了一种非常适合进行复杂系统开发的语言。下面我们将深入探讨Python中的面向对象编程基础。 一、类与对象 1. **类(Class)**:类是面向对象编程的基础,...
一般要用到递归,就要判断对象是否和父类型是否一样 这里演示简单的对象递归,还有数组递归类似。 var obj = { a:{w:1,y:2,x:3}, b:{s:4,j:5,x:6}, ...以上这篇使用递归遍历对象获得value值的实现方法
默认情况下,当一个对象被当作原始值(如字符串、数字)处理时,JavaScript会调用该对象的`valueOf`方法来获取这个基本值。这个过程发生在隐式类型转换时,比如在比较操作、算术运算或者作为字符串连接的一部分时。 ...
3. **错误处理**:如果在管道中某个函数抛出错误,`value-pipe`会捕获并返回一个错误对象,这可以帮助你在处理过程中处理异常情况。 4. **自定义管道**:你可以根据需求创建自己的管道类,扩展`value-pipe`的功能,...
8. **接口一致性**:通过定义统一的接口,值对象可以使客户端代码更加简洁,因为它们总是知道如何处理值对象,而无需关心具体的实现细节。 9. **单元测试**:值对象的定义清晰,有助于编写针对性的单元测试,确保其...
在Android开发中,Spinner是一个非常常见...理解如何设置和处理Spinner的选中事件,以及如何获取选中项的text和value,是Android开发中必备的技能之一。通过实践上述步骤和参考示例代码,你应该能够熟练掌握这一功能。
Grafna Dashboard 中,支持 `variables` 变量, 以下拉列表的形式展示在左上角,用户可选择其内容,下面的 Panel 中的对象查询中增加 $xxx 即可实现对象的切换, 比较方便。 问题: 常规实现没有问题,但对于下拉列表...
auto-value-firebase, 创建Firebase数据库对象的AutoValue扩展 AutoValue: Firebase扩展对于与 Firebase实时数据库兼容的值类,必须:包含 public"获取"-prefixed访问器或者 public 字段,以及包含一个空的或者...
- **动态数据模型**:栈中可以包含多个对象,这使得Value Stack能够处理复杂的业务场景,例如,同时处理多个Action对象或共享数据。 - **灵活性**:OGNL支持表达式计算,不仅可以访问属性,还能调用方法,甚至执行...