BasicObject 类
BasicObject
是 Ruby 中所有类的父类。它是一个显式空白类。
BasicObject
可用于创建独立于 Ruby 对象层次结构的对象层次结构、代理对象(例如 Delegator
类),或其他必须避免 Ruby 方法和类造成命名空间污染的用途。
为了避免为其他用户污染 BasicObject
,应创建 BasicObject
的适当命名子类,而不是直接修改 BasicObject
class MyObjectSystem < BasicObject end
BasicObject
不包括 Kernel
(用于诸如 puts
之类的函数),且 BasicObject
位于标准库的命名空间之外,因此如果不使用完整类路径,将找不到常见类。
可以使用多种策略为 BasicObject
的子类提供标准库的有用部分。子类可以 include Kernel
以获取 puts
、exit
等。可以创建并包含自定义的类似 Kernel 的模块,或可以通过 method_missing
使用委托。
class MyObjectSystem < BasicObject DELEGATE = [:puts, :p] def method_missing(name, *args, &block) return super unless DELEGATE.include? name ::Kernel.send(name, *args, &block) end def respond_to_missing?(name, include_private = false) DELEGATE.include?(name) or super end end
可以通过引用根目录中的所需常量(如 ::File
或 ::Enumerator
)来在 BasicObject
子类中获取 Ruby 标准库中的类和模块。与 method_missing
类似,const_missing 可用于将常量查找委托给 Object
class MyObjectSystem < BasicObject def self.const_missing(name) ::Object.const_get(name) end end
此处内容¶ ↑
以下是为 BasicObject 定义的方法
-
::new
: 返回一个新的 BasicObject 实例。 -
!
: 返回self
的布尔否定值:true
或false
。 -
!=
: 返回self
和给定对象是否不相等。 -
==
: 返回self
和给定对象是否相等。 -
__id__
: 返回self
的整数对象标识符。 -
__send__
: 调用由给定符号标识的方法。 -
equal?
: 返回self
和给定对象是否是同一对象。 -
instance_eval
:在self
的上下文中评估给定的字符串或块。 -
instance_exec
:在self
的上下文中执行给定的块,传递给定的参数。
公共类方法
返回一个新的 BasicObject
。
#define rb_obj_initialize rb_obj_dummy0
公共实例方法
布尔否定。
VALUE rb_obj_not(VALUE obj) { return RBOOL(!RTEST(obj)); }
如果两个对象不相等,则返回 true,否则返回 false。
VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2) { VALUE result = rb_funcall(obj1, id_eq, 1, obj2); return rb_obj_not(result); }
相等性 — 在 Object
级别,==
仅当 obj
和 other
是同一个对象时才返回 true
。通常,此方法在子类中被覆盖以提供特定于类的含义。
与 ==
不同,equal?
方法永远不应该被子类覆盖,因为它用于确定对象标识(即,当且仅当 a
是与 b
相同的对象时,a.equal?(b)
才为 true)
obj = "a" other = obj.dup obj == other #=> true obj.equal? other #=> false obj.equal? obj #=> true
如果 obj
和 other
引用同一个哈希键,则 eql? 方法返回 true
。这被 Hash
用于测试成员的相等性。对于 eql? 返回 true
的任何一对对象,这两个对象的哈希值必须相等。因此,任何覆盖 eql? 的子类也应该适当地覆盖 hash。
对于 Object
类的对象,eql? 与 ==
同义。子类通常通过将 eql? 别名为它们重写的 ==
方法来延续此传统,但也有例外。Numeric
类型(例如)在 ==
中执行类型转换,但在 eql? 中不执行,因此
1 == 1.0 #=> true 1.eql? 1.0 #=> false
VALUE rb_obj_equal(VALUE obj1, VALUE obj2) { return RBOOL(obj1 == obj2); }
为 obj
返回一个整数标识符。
对于给定对象,在所有对 object_id
的调用中都将返回相同的数字,并且没有两个活动对象将共享一个 id。
注意:为了优化,某些内置类的对象会被重复使用。对于立即值和冻结的字符串文字来说就是这种情况。
BasicObject
实现 __id__
,Kernel
实现 object_id
。
立即值不是按引用传递的,而是按值传递的:nil
、true
、false
、Fixnum、符号和一些 Float。
Object.new.object_id == Object.new.object_id # => false (21 * 2).object_id == (21 * 2).object_id # => true "hello".object_id == "hello".object_id # => false "hi".freeze.object_id == "hi".freeze.object_id # => true
VALUE rb_obj_id(VALUE obj) { /* * 32-bit VALUE space * MSB ------------------------ LSB * false 00000000000000000000000000000000 * true 00000000000000000000000000000010 * nil 00000000000000000000000000000100 * undef 00000000000000000000000000000110 * symbol ssssssssssssssssssssssss00001110 * object oooooooooooooooooooooooooooooo00 = 0 (mod sizeof(RVALUE)) * fixnum fffffffffffffffffffffffffffffff1 * * object_id space * LSB * false 00000000000000000000000000000000 * true 00000000000000000000000000000010 * nil 00000000000000000000000000000100 * undef 00000000000000000000000000000110 * symbol 000SSSSSSSSSSSSSSSSSSSSSSSSSSS0 S...S % A = 4 (S...S = s...s * A + 4) * object oooooooooooooooooooooooooooooo0 o...o % A = 0 * fixnum fffffffffffffffffffffffffffffff1 bignum if required * * where A = sizeof(RVALUE)/4 * * sizeof(RVALUE) is * 20 if 32-bit, double is 4-byte aligned * 24 if 32-bit, double is 8-byte aligned * 40 if 64-bit */ return rb_find_object_id(obj, cached_object_id); }
调用由 symbol 标识的方法,向其传递指定的任何参数。当方法由字符串标识时,该字符串将转换为符号。
BasicObject
实现 __send__
,Kernel
实现 send
。当 obj 具有与 Socket
相同的方法名称时,__send__
比 send
更安全。另请参见 public_send
。
class Klass def hello(*args) "Hello " + args.join(' ') end end k = Klass.new k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
VALUE rb_f_send(int argc, VALUE *argv, VALUE recv) { return send_internal_kw(argc, argv, recv, CALL_FCALL); }
相等性 — 在 Object
级别,==
仅当 obj
和 other
是同一个对象时才返回 true
。通常,此方法在子类中被覆盖以提供特定于类的含义。
与 ==
不同,equal?
方法永远不应该被子类覆盖,因为它用于确定对象标识(即,当且仅当 a
是与 b
相同的对象时,a.equal?(b)
才为 true)
obj = "a" other = obj.dup obj == other #=> true obj.equal? other #=> false obj.equal? obj #=> true
如果 obj
和 other
引用同一个哈希键,则 eql? 方法返回 true
。这被 Hash
用于测试成员的相等性。对于 eql? 返回 true
的任何一对对象,这两个对象的哈希值必须相等。因此,任何覆盖 eql? 的子类也应该适当地覆盖 hash。
对于 Object
类的对象,eql? 与 ==
同义。子类通常通过将 eql? 别名为它们重写的 ==
方法来延续此传统,但也有例外。Numeric
类型(例如)在 ==
中执行类型转换,但在 eql? 中不执行,因此
1 == 1.0 #=> true 1.eql? 1.0 #=> false
在接收器 (obj) 的上下文中评估包含 Ruby 源代码的字符串或给定的块。为了设置上下文,在代码执行期间,变量 self
设置为 obj,从而使代码可以访问 obj 的实例变量和私有方法。
当 instance_eval
给定一个块时,obj 也作为块的唯一参数传递。
当 instance_eval
给定一个 String
时,可选的第二个和第三个参数提供一个文件名和一个起始行号,用于报告编译错误。
class KlassWithSecret def initialize @secret = 99 end private def the_secret "Ssssh! The secret is #{@secret}." end end k = KlassWithSecret.new k.instance_eval { @secret } #=> 99 k.instance_eval { the_secret } #=> "Ssssh! The secret is 99." k.instance_eval {|obj| obj == self } #=> true
static VALUE rb_obj_instance_eval_internal(int argc, const VALUE *argv, VALUE self) { return specific_eval(argc, argv, self, TRUE, RB_PASS_CALLED_KEYWORDS); }
在接收器 (obj) 的上下文中执行给定的块。为了设置上下文,在代码执行时将变量 self
设置为 obj,使代码能够访问 obj 的实例变量。参数作为块参数传递。
class KlassWithSecret def initialize @secret = 99 end end k = KlassWithSecret.new k.instance_exec(5) {|x| @secret+x } #=> 104
static VALUE rb_obj_instance_exec_internal(int argc, const VALUE *argv, VALUE self) { return yield_under(self, TRUE, argc, argv, RB_PASS_CALLED_KEYWORDS); }
私有实例方法
当 obj 收到它无法处理的消息时,由 Ruby 调用。symbol 是所调用方法的符号,而 args 是传递给它的任何参数。默认情况下,当调用此方法时,解释器会引发错误。但是,可以覆盖该方法以提供更动态的行为。如果决定不处理特定方法,则应调用 super,以便祖先可以选取缺失的方法。下面的示例创建了一个类 Roman
,它响应名称由罗马数字组成的消息,返回相应的整数。
class Roman def roman_to_int(str) # ... end def method_missing(symbol, *args) str = symbol.id2name begin roman_to_int(str) rescue super(symbol, *args) end end end r = Roman.new r.iv #=> 4 r.xxiii #=> 23 r.mm #=> 2000 r.foo #=> NoMethodError
static VALUE rb_method_missing(int argc, const VALUE *argv, VALUE obj) { rb_execution_context_t *ec = GET_EC(); raise_method_missing(ec, argc, argv, obj, ec->method_missing_reason); UNREACHABLE_RETURN(Qnil); }
每当向接收器添加单例方法时,作为回调调用。
module Chatty def Chatty.singleton_method_added(id) puts "Adding #{id.id2name}" end def self.one() end def two() end def Chatty.three() end end
生成
Adding singleton_method_added Adding one Adding three
#define rb_obj_singleton_method_added rb_obj_dummy1
每当从接收器中移除单例方法时,作为回调调用。
module Chatty def Chatty.singleton_method_removed(id) puts "Removing #{id.id2name}" end def self.one() end def two() end def Chatty.three() end class << self remove_method :three remove_method :one end end
生成
Removing three Removing one
#define rb_obj_singleton_method_removed rb_obj_dummy1
每当在接收器中未定义单例方法时,作为回调调用。
module Chatty def Chatty.singleton_method_undefined(id) puts "Undefining #{id.id2name}" end def Chatty.one() end class << self undef_method(:one) end end
生成
Undefining one
#define rb_obj_singleton_method_undefined rb_obj_dummy1