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

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

有个新手问题,一直很困惑,在类内定义一个实例变量@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=赋值又是可以的呢?没猜出根结 哪位高手能解释下吗,感谢了!

共收到 7 条回复

第二个问题: 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,是因为rubycase 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

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