Ruby 实例变量的一个坑

Niatruc · 2018年12月16日 · 最后由 sevk 回复于 2018年12月18日 · 1671 次阅读
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 路过的老铁支持支持哈哈谢谢谢谢~👽

不是实例变量的坑,是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 是类方法。 不是实例方法。

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