gpt4 book ai didi

ruby - 模仿另一个 Ruby 类,使对象通过 === 类型检查

转载 作者:数据小太阳 更新时间:2023-10-29 06:45:59 25 4
gpt4 key购买 nike

我想创建一个充当特定类的对象,例如 Fixnum,但不是该类或其子类的实例。

这有多种用例。在 Fixnum 案例中,我想定义一个更具体的整数类型,它本质上是 Fixnum 但也实现了一些额外的逻辑。我不能对 Fixnum 本身进行子类化,因为不能对 Fixnum 和 Symbol 等直接类型进行子类化。

另一个用例是在自动化测试中进行模拟:有时您想要创建一个对象,它的行为类似于某个类(通常是模型实例),但出于技术原因不是该类的实例。

下面是如何创建一个特定的整数类型,将所有方法委托(delegate)给一个内部存储的 fixnum:

require 'delegate'
require 'forwardable'

# integer representing a page number
class PageNumber < DelegateClass(Integer)
extend Forwardable

def initialize(value, name)
@name = name
super(value)
end

def inspect
"#{@name} #{to_i}"
end

alias_method :to_i, :__getobj__
def_delegators :to_i, :instance_of?, :kind_of?, :is_a?
end

这个对象可以通过 is_a? 和类似的检查:

page = PageNumber.new(1, "page")
page.is_a? Fixnum #=> true

但是我做的任何事情都无法让它通过 Module#===类型检查:

# my problem:
Fixnum === page #=> false

我的对象未能通过此检查这一事实非常不幸,因为 === 方法在 case 语句内部使用:

case page
when Fixnum
# it will never get here
when String
# ...
else
# ...
end

我的问题是如何创建一个模拟类型来通过 === 检查 而不 在构建时增加 === 方法-在类里面?

最佳答案

如果我们谈论 MRI1,答案很简单:你不能。

Module#=== 方法实际上是一个 aliasrb_obj_is_kind_of C API 方法。后者的实现很短,我将其粘贴在这里:

VALUE
rb_obj_is_kind_of(VALUE obj, VALUE c)
{
VALUE cl = CLASS_OF(obj);

/* Type checking of `c' omitted */

while (cl) {
if (cl == c || RCLASS_M_TBL(cl) == RCLASS_M_TBL(c))
return Qtrue;
cl = RCLASS_SUPER(cl);
}
return Qfalse;
}

正如你所看到的,这个方法遍历了被检查对象的祖先,并通过两种方式进行比较:首先,它检查祖先是否与传递的模块相同,然后,它检查它们是否有相同的方法表。

后一种检查是必需的,因为Ruby中包含的模块看似插入了继承链,但由于一个模块可能包含在其他几个模块中,所以插入链中的不是真正的模块,而是一个代理对象,它有指向原始模块的常量和方法表。

例如,让我们看一下 Object 的祖先:

ruby-1.9.2-p136 :001 > Object.ancestors
=> [Object, Kernel, BasicObject]
ruby-1.9.2-p136 :002 > Object.ancestors.map { |mod| Object.new.is_a? mod }
=> [true, true, true]

在这里,ObjectBasicObject 将通过第一次检查成功比较,而 Kernel 将通过第二次检查成功比较。

即使您尝试创建(使用 C 扩展)一个代理对象来欺骗 rb_obj_is_kind_of 方法,它也需要与真实的 具有相同的方法表>Fixnum,这将有效地包括所有 Fixnum 的方法。


1 我研究了 Ruby 1.9 的内部结构,但它们在 1.8 中的行为方式完全相同。

关于ruby - 模仿另一个 Ruby 类,使对象通过 === 类型检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6973242/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com