新手问题 Ruby 的实例变量的 scope

uestc_bird · 2016年05月10日 · 最后由 geekjj 回复于 2016年06月02日 · 2774 次阅读
class A
  @i = "hi"

  def say
    puts "#{@i}"
  end

end

ins = A.new
ins.say
  1. ins.say 的输出是什么?
  2. 实例变量@i的 scope 是什么?

你想问个啥?

#1 楼 @qinfanpeng 估计他想问的是“域”的问题。建议楼主先把什么是面向对象搞清楚

A.instance_variable_get :@i
A.instance_eval { @i }
A.class_eval { @i }
  1. 代码格式化
  2. @ 为类实例变量,属于整个实例

#3 楼 @catherine 对的,我问的就是 ruby 里面变量的作用域的问题,不过变量的作用域问题跟面向对象貌似没有啥关系。。。。

#5 楼 @small_fish__ @i属于整个实力,为什么在方法里面不能使用它?

#8 楼 @uestc_bird 类本身也是一个对象实例。与 new 的实例是不同的,@只能在方法内定义。

class A
  @i = "hi"
  puts "此时self是#{self}"
  def say
    puts "此时self是#{self}, A的一个实例"
    puts "#{@i}"
  end

end

ins = A.new
ins.say

两个@i不是同一个东西,def会打开新的作用域。 def里面的@i好理解,就是 A 的每一个实例的实例变量。 def外面的@i,首先要知道 A 是 Class 的一个实例

ins.class # A
A.class   # Class

一个实例自然可以拥有自己的实例变量

  1. A 是 class 的实例,A.new 是 A 的实例。
  2. @定义的变量,如果没有赋值,使用的时候,将是 nil 而不会报错。
  3. 你给出的例子 @i 赋值的时候,该变量属于 A , 而不是 A.new,所以你若想得到 @i , 你可以通过 A.instance_variable_get(:@i) 得到。

#6 楼 @uestc_bird 楼上几位都说的很好了。补充一点便于你理解他们的所说观点:

class A
  @i = "hi"
  def say
    puts "#{@i}"
  end
end

# 上下两中写法几乎一样

A = Class.new do 
  @i = "hi"
  def say
    puts "#{@i}"
  end
end

感谢各位的解答,貌似有点理解了现在。

#12 楼 @qinfanpeng

:plus1 :clap :sm

再补充一点

class A
  @i = "hi"
  def self.say
    puts "#{@i}"
  end
end

A.say # 'hi' 
piecehealth 如何访问 @c 提及了此话题。 06月02日 14:42

比较容易理解一点的方法就是你要知道实例变量是定义在 self 上的,所以想搞清楚这两个@i有什么区别首先要知道这两个地方的 self 有什么区别。尝试如下:

class A
  @i = "hi"
  puts "First place: self is #{self}, @i is #{@i}."

  # 实例方法
  def say
    puts "Second place: self is #{self}, @i is #{@i}."
  end

  # 类方法,类似于java的static方法
  def self.say
    puts "Third place: self is #{self}, @i is #{@i}."
  end
end

a = A.new
a.say
A.say

结果如下:

First place: self is A, @i is hi.
=> :say
[68] pry(main)> 
[69] pry(main)> a = A.new
=> #<A:0x0000000790cd90>
[70] pry(main)> a.say
Second place: self is #<A:0x0000000790cd90>, @i is .
=> nil
[71] pry(main)> A.say
Third place: self is A, @i is hi.
=> nil

这里可以很清楚的看到第一个@i定义的时候 self 是 A,所以第一个实例变量 i 是定义在 A 上的;第二个地方 self 是#<0x0000000790cd90> 也就是 A 的一个匿名类(可以理解为实例 a),这个时候调用定义在该匿名类(可以理解为实例 a)上的实例变量 i,明显未定义过,所以为 nil;第三个地方 self 是 A,调用定义在 A 上的实例变量 i,故而有值。0x0000000790cd90>

除了 self 的概念,ruby 中还有当前类的概念,掌握了这两个概念,这些问题都可以迎刃而解。

最后,推荐你看一下 ruby 元编程。

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