新手问题 有个新手问题,一直很困惑,在类内定义一个实例变量 @x,在调用时候什么时候用 @x,什么时候省略直接用 x,

bluetea · 2015年01月01日 · 最后由 jasontang168 回复于 2015年04月29日 · 2386 次阅读

有个新手问题,一直很困惑,在类内定义一个实例变量@x,在调用时候什么时候用@x,什么时候省略直接用 x, 接触 ruby 时间不长,现在看《ruby 基础教程》第四版 125 页的一个程序段

class Point
  attr_accessor :x, :y

  def initialize(x=0, y=0)
    @x, @y = x, y
  end

 def [](index)

  case index
  when 0
    x
  when 1
    y
  else
    raise ArgumentError ," out of range #{index}"
  end

 end

 def []=(index, val)

  case index
  when 0
    self.x= val  #这里到底是用self.x还是 @x,我看两种结果都是对的,很疑惑
  when 1
    self.y= val
  else
    raise ArgumentError, "out of range #{index}"
  end

  end
end

p1 = Point.new(22,11)
p p1[0]
p p1[0] = 333
p p1[0]

self.x= val #这里到底是用self.x还是 @x,我看两种结果都是对的,很疑惑,那为啥直接写 x 无法改变值呢 这行代码很疑惑,另外当把这行代码改为如下的时候: attr_reader :x, :y 执行的时候 @x 和 x 的时候执行就有区别了,attr_reader 的时候,再赋值的是 会提示没有 x=方法,我了解 attr_reader 不会创建 x=方法,但是为啥@x=赋值又是可以的呢?没猜出根结 哪位高手能解释下吗,感谢了!

第二个问题: attr_accessor会自动生成 get 和 set 方法。也就是会 attr_reader 和 attr_writer,可读可写。当你改为 attr_reader 的时候,这个实例变量设置为可读 不可写,所以会出现,没有 x= 方法。

#1 楼 @awking 嗯嗯,非常感谢,我了解 attr_reader 不会创建 x=方法,但是为啥@x=赋值又是可以的呢?这段程序中 x 是局部变量,@x是实例变量,这两个到底有啥关系呢?

第一个问题,@x 意思是实例变量,而 self.x 是类会传递给 x 值然后返回一个实例变量 @x,二者是不同的。而 x 只是类中实例方法内的普通的局部变量。

@x= 只是赋值。

attr_reader :x
#等同于
def x
  @x
end

只会在你 obj = Point.new(22,33) 时候,不能通过 obj.x = 999,这句会报错。

在类里面,修改 @x 是很普通的事情。

所谓的实例变量,是属于一个一个对象的,他的作用域是作用在整个对象上的。

case index
  when 0
    x  # 这里的x 等价与 @x, self.x
  when 1
    y
  else
    raise ArgumentError ," out of range #{index}"
  end
def []=(index, val)

  case index
  when 0
    self.x= val  #这里用self.x @x都可以。但是你如果用 x= val.ruby会认为你要创建一个局部变量x,而不是修改原     来实例变量的值 
  when 1
    self.y= val
  else
    raise ArgumentError, "out of range #{index}"
  end

  end

#4 楼 @awking 嗯嗯,非常感谢,我大概明白了,我重复你下,您看我说的对吗 代码 1

case index
  when 0
    x  
==begin 这里的x 等价与 @x,是因为ruby在case when结构的代码段读取x变量case内部作用域没有
变量x所以去外部找寻找变量以前学过一点儿cc语言在本作用域没找到变量会去外部找离他最近的变量值所以找到了@x),结果找到了@x,所以就把@x的值输出这里x 就成为了@x的简称--这种说法对吗
==end
  when 1
    y
  else
    raise ArgumentError ," out of range #{index}"
  end

代码 2:

def []=(index, val)

  case index
  when 0
    self.x= val 
==begin
这里用self.x @x都可以但是你如果用 x= val.ruby会认为你要创建一个局部变量x所以根本不会去外部的作用域去找那个x的变量而是在本作用域创建一个局部变量x然后赋值给这个x了
==end
  when 1
    self.y= val
  else
    raise ArgumentError, "out of range #{index}"
  end

  end

无论如何非常感谢!

#4 楼 @awking 非常感谢,我明白了,我改了下代码,可以看出来如果不赋值给@x,或者 self.x 的话,x 的 object_id 是不一样的,非常感谢!

class Point
  attr_accessor :x, :y

  def initialize(x=0, y=0)
    @x, @y = x, y

  end

 def [](index)

  case index
  when 0
    puts "x objcet_id = #{x.object_id}\n@x object id = #{@x.object_id}"
  when 1
    y
  else
    raise ArgumentError ," out of range #{index}"
  end

 end

 def []=(index, val)

  case index
  when 0
    x= val
    puts  "x的objcet_id 是:#{x.object_id}"
    puts "@x的object id 是: #{@x.object_id}"
    puts "self的x的object_id 是: #{self.x.object_id}"
  when 1
    y= val
  else
    raise ArgumentError, "out of range #{index}"
  end

  end
end

p1 = Point.new(22,11)
p p1[0]
p p1[0] = 333

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