我应该使用什么约定的实例变量?

Les*_*nis 3 ruby

Ruby代码中是否使用了任何实例变量约定?也就是说,我注意到,在examples部分中,实例变量使用'@'初始化,然后代码使用不带'@'的变量名:

class BookInStock
  attr_reader: isbn
  attr_accessor: price

  def initialize (isbn, price)
    @isbn = isbn
    @price = Float (price)
  end

  def price_in_cents
    Integer (price * 100 + 0.5)
  end
end
Run Code Online (Sandbox Code Playgroud)

还有一些例子,代码,实例变量一直使用前缀'@'

class BookStock

  def set_price (price)
    @price = price
  end

  def get_price
    @price
  end
end
Run Code Online (Sandbox Code Playgroud)

这些记录有什么区别?什么时候我应该只在对象的初始化和所有类方法中使用'@'?

ven*_*enj 6

在第一个示例中,@price是一个实例变量.

在方法定义中price_in_cents,price实际上是一个方法调用price().由于Ruby的语法糖,()省略了.

它看起来没有明确的定义price(),但attr_accessor :price定义了两者price(),price=(value)也就是getter和setter.您可以尝试注释掉该attr_accessor :price行,当BookInStock实例调用时,您将获得"未定义的局部变量或方法"异常price_in_cents.

实例变量始终具有@前缀.如果未定义访问者方法,则不能使用不带@前缀的名称.


mol*_*olf 6

@如果已为此变量定义了属性读取器(使用attr_reader或attr_accessor),则只能使用实例变量名称.这是一个轻量级助手,用于创建返回实例变量值的方法.

区别在于使用类的公共接口或访问私有数据之间的问题.例如,建议在子类或包含的模块中使用公共接口.这确保了封装.因此,您不应该从子类或模块中访问实例变量.

在类本身中,问问自己这个问题:如果属性的实现发生了变化,我的使用属性是否也会发生变化?如果答案是肯定的,请直接使用实例变量; 如果不是,请使用public属性.

一个例子.假设我们有一个Person代表一个人的类,并且应该包含该人的名字.首先是这个版本,只有一个简单的name属性:

class Person
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def blank?
    !@name
  end

  def to_s
    name
  end
end
Run Code Online (Sandbox Code Playgroud)

注意我们是如何使用的实例变量的blank?方法,但公共属性的to_s方法.这是故意的!

让我们说在重构步骤中我们决定Person该类应该跟踪a first_name和last_name单独.

class Person
  def initialize(first_name, last_name)
    @first_name, @last_name = first_name, last_name
  end

  def name
    "#{@first_name} #{@last_name}"
  end

  def blank?
    !@first_name and !@last_name
  end

  def to_s
    name
  end
end
Run Code Online (Sandbox Code Playgroud)

我们现在将name属性更改为常规方法,该方法根据人的名字和姓氏组成名称.我们现在可以看到可以保持相同的实现to_s.但是,blank?需要更改,因为它依赖于基础数据.这就是to_s使用该属性但blank?使用了实例变量的原因.

当然,区别并不总是容易的.如有疑问,请选择公共API而不是访问私有数据.