Ruby中BasicObject的单例类的单例类

时间:2018-07-02 08:57:13

标签: ruby metaprogramming eigenclass

这主要是一个“学术”课程,但实际情况如下:

根据此Ruby本征类图(略作编辑):

Possibly-wrong Ruby eigenclass diagram

file = new File(imagePath); FileUploadService service = getRetrofit().create(FileUploadService.class); // create RequestBody instance from file RequestBody requestFile = RequestBody.create( MediaType.parse(getContentResolver().getType(imageUri)), file ); // MultipartBody.Part is used to send also the actual file name MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile); Call<ResponseBody> call = service.upload(body); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { Log.v("Upload", "success"); String resource = BASE_URL + "images/" + file.getName(); sendMessage(resource, recieverBareid); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.v("Upload", "failed"); } }); BasicObject.singleton_class.singleton_class.superclass

但是,在Ruby解释器(Ruby v2.5.1)上运行它,结果发现ClassBasicObject.singleton_class.singleton_class.superclass而不是#<Class:Class>。因此,该图是在说谎还是我缺少什么?

该图来自我在Freenode的Ruby IRC聊天的一个用户。但是,它已被许多其他用户多次引用,并被视为Ruby对象模型圣经。

1 个答案:

答案 0 :(得分:2)

Ruby解释器的行为非常合理,因为:

  • Child类扩展Parent时,Ruby对其进行设置,以便单例类#<Class:Child>也扩展了#<Class:Parent>;和
  • BasicObject.singleton_classClass的子类,因此BasicObject.singleton_class.singleton_class将是#<Class:Class>的子类

验证相等性:

BasicObject.singleton_class.singleton_class.superclass.equal?(Class.singleton_class)
#=> true

这引出了下一个问题–为什么#<Class:BaseObject>首先扩展Class?按照上述规则,由于BaseObject没有超类-即BaseObject.superclassnil-逻辑上应该是其单例类也不具有超类。

答案是,#<Class:BaseObject>扩展Class可以确保单例类在继承层次结构中的一致性。以这个Ruby对象为例:

obj = "a string"

这是一个公认的概念,不是将obj仅仅作为String的实例,而是可以将其视为其自己的singleton类的(唯一)实例, String的子类。那就是:

obj.class.equal?(obj.singleton_class.superclass)
#=> true

同样合理的是,对类实例也应同样适用。但这并不矛盾,因为它与上述规则冲突,其中Child类的单例类的超类是其Parent类的单例类。

class Foo; end

Foo.class
#=> Class

Foo.singleton_class.superclass
#=> #<Class:Object>      <-- not equal to Class!

# because:
Foo.superclass
#=> Object

但是可以通过将Class放在单例类继承层次结构的顶部来解决此矛盾:

Foo.singleton_class.superclass
#=> #<Class:Object>

Foo.singleton_class.superclass.superclass
#=> #<Class:BasicObject>

Foo.singleton_class.superclass.superclass.superclass
#=> Class

这样,即使Foo.singleton_class.superclass不等于Foo.class,通过沿继承链走,它最终也确实到达了那里。