Ruby 实例变量的一个坑

Niatruc · 2018年12月16日 · 最后由 sevk 回复于 2018年12月18日 · 728 次阅读
class  C
  class << C
    @c = 1

    def  f
      @c 
    end
  end
end

C.f #=> nil

如上代码,当我自以为是地认为@c是类C的实例变量时,结果却非我想象的那样(期望C.f结果为1,实际为nil) 翻开笔记复习、巩固一下以前所学的Ruby内部机制。 原来,class << C打开了C的元类,所以从class << C到它的end之间的作用域是C的元类的作用域,于是乎@c就成了C的元类的实例变量:

C.singleton_class.class_eval { @c } #=> 1

顺便自卖自夸一波自己正在做的一个查询和操作数据库的工具。做这个东西的起因是,之前做开发的时候,插入测试用的数据要么用navicat之类的工具手动地一行一行录入,要么写sql脚本批量插入,都不是那么方便,又找不到其他好办法,有点烦;另外有时项目涉及到多个不同类型的数据库(mysql/oracle/hbase等),又没有比较好的集大成的工具(navicat有集合多种数据库管理功能的版本,没用过;有一个叫squirrel的,用起来不是那么好,卡bug……),于是促成了爱撸码的我的小小主意——自己设计一个命令行数据库工具,挣脱sql语句的束缚,自己搞一套规则👽 于是乎,借鉴ActiveRecord、Sequels等框架的思想,利用Ruby语法灵活多变的特性,自己开搞一套,也可以多练习用Ruby撸码。现在做好了mysql的查询功能,以及一些命令行补全功能,后面找时间做‘增删改’的功能。效果如下:

补全操作,从库名到表名到对表的操作命令名:

‘cd’操作,进入到库/表的上下文:

条件查询,用散列封装:

项目链接:https://github.com/Niatruc/zombiehome 路过的老铁支持支持哈哈谢谢谢谢~👽

共收到 6 条回复

不是实例变量的坑,是def打开一个跟上下文不联通的作用域,不管是不是在singleton_class里,要理解ruby的作用域,代码应该是

class  C
  @c = 1
  class << C
    def  f
      @c
    end
  end
end

你直接将@c写在类里(元类也是类),而不是写在方法里,这种变量是类实例变量(class instance variable),而不是实例变量。它跟实例变量的用法并不一样。所以这个问题并不是实例变量的坑。

怪我表达不当咯😂 😂 我只是用‘坑’这个字表达自己在用实例变量的时候犯了错误,踩坑了……另外不管是实例的实例变量还是类的实例变量,我都当‘实例变量’来记了,它们只是属主不一样罢了。

class << C 这个是什么意思? 是不是相当于

class C
  def  f
    @c
  end
end
sevk 回复

应该是相当于

class C
  def self.f
    @c
  end
end
liukun_lk 回复

哦,那楼主应该用 @@c 类变量, 因为 self.f 是类方法。 不是实例方法。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册