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

bluetea · January 01, 2015 · Last by jasontang168 replied at April 29, 2015 · 2359 hits

有个新手问题,一直很困惑,在类内定义一个实例变量@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,是因为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

You need to Sign in before reply, if you don't have an account, please Sign up first.