Ruby中self为类或实例时如何获取不带内存地址的正确类名
问题描述
开发了提供日志打印能力的Ruby模块,部分类通过extend引入该模块,其余类通过include引入该模块,日志打印逻辑需要传入对应类名作为参数。
初始使用如下方式调用日志方法:
global_logger.call(level, self, msg)
不同模块引入方式会输出两种不同结果:
- 模块被
extend引入时,输出格式为WARN -- Some::Class: some msg,类名展示正常 - 模块被
include引入时,输出格式为WARN -- #<Some::OtherClass:0x00007fdc04907710>: some msg,展示带内存地址的实例字符串,不符合预期
如果将传入参数改为self.class,会出现新的问题:
include场景下类名展示正常extend场景下会输出固定内容Class,同样不符合预期
核心需求:在无法预先判断self是类本身还是类实例的前提下,获取正确的类名,避免输出带内存地址的实例对象表示字符串。
解决方案
直接通过判断self是否为类/模块类型,动态选择取值即可,代码如下:
# 统一获取日志归属的类对象 target_class = self.is_a?(Module) ? self : self.class global_logger.call(level, target_class, msg)
实现原理
- 当模块通过
extend引入时,日志方法会作为类方法挂载到目标类上,方法执行时的self直接指向目标类本身。Ruby中所有类、模块都是Module类的子类实例,因此self.is_a?(Module)判断返回true,直接返回self即可拿到正确的类对象。 - 当模块通过
include引入时,日志方法会作为实例方法挂载到目标类上,方法执行时的self指向类的实例对象。普通业务实例不属于Module体系,判断返回false,此时取self.class即可拿到实例对应的类对象。
拿到正确的类对象后,后续无论是调用.name获取全限定类名字符串,还是做自定义格式化,都不会出现带内存地址的实例字符串问题。
内容的提问来源于stack exchange,提问作者Peter R
相关产品推荐
相关产品推荐

