4

我在理解 Ruby 中变量和符号的语法时遇到了一些麻烦。我正在阅读一本名为 Agile Web Development with Rails 4 的书。我正在尝试同时学习 Ruby 和 Rails,以便我可以构建网站。

我一直在看的书和教程,有时候变量前面有“@”符号,然后有些变量前面没有@符号。它们之间有什么区别?

另外,我对结肠感到困惑。有时我看到冒号在前面的变量,例如:order,然后我看到冒号在末尾的变量,例如冒号:。我不明白结肠在做什么。

请帮助我理解 Ruby 语法。

4

4 回答 4

10

以 开头@的变量是实例变量,在其他语言中是“属性”。而“经典”变量在其方法/块的范围内是本地的,而实例变量对于特定instance的对象来说是本地的,例如:

class Foo

  def initialize(bar)
    @bar = bar
  end

  def bar
    @bar # the variable is specific to this instance
  end

  def buzz
    buzz = 'buzz' # this variable is not accessible outside of this method
  end

end

您可能还会看到以 开头的变量@@,它们是类变量,可以被类的每个实例访问并与子类的每个实例共享。通常不鼓励使用这些变量,主要是因为子类共享变量,这会导致很多混乱。

在 Ruby 中,一切都是对象,类是对象(类的实例Class),因此您还可以拥有类实例变量:

class Foo

  def self.bar
    @bar #we are in class Foo's scope, which is an instance of class Class
  end

  def self.bar=(bar)
    @bar = bar
  end

  def bar
    @bar # Foo.new.bar != Foo.bar 
  end

end

您所说的“带冒号的变量”不是变量。它们是一种特殊类型的字符串,称为符号,它是不可变的,并且针对解释器的快速识别进行了优化,事实上,它们作为指针在内部存储,因此这:this == :this是一个非常快速的操作。

此属性使它们成为哈希键的良好候选者,因为它们提供快速检索或“标志”传递给方法;将它们视为一种松散的常数,“代表”他们所说的话。它们的不变性也很危险:曾经创建的所有符号都不会被垃圾收集;通过创建数千个符号很容易造成内存泄漏,因此请明智地使用它们。

更新,因为 ruby​​ 2.2 符号在某些情况下可能会被垃圾收集(当没有保留参考并且不需要比较时)

于 2013-11-04T15:38:12.430 回答
3

带有@符号的变量是实例变量。这意味着只要声明它们的类的实例持续存在,它们就会持续存在。因此,如果您有一个名为的类Message并且每条消息都有一个名为 的变量@subject,那么当您实例化一条新消息时,只要消息对象本身存在,它就会将该主题变量保留在内存中。现在,如果它没有@符号,一旦它在“超出范围”中声明的函数又名完成,该变量将“丢失”,因为函数完成并且内存被 Ruby VM 回收。还有以两个@符号开头的“类变量”。这意味着该变量在类的所有实例之间共享。

至于冒号,如果它在变量之前,则意味着它是一个“符号”,它通常用作 Ruby 中哈希和其他数据位的标识符。如果它位于单词的末尾,则意味着它是 Ruby 1.9+ 语法中哈希标识符的关键部分。

于 2013-11-04T15:41:54.870 回答
2

有时变量前面有“@”符号,然后有些变量前面没有@符号。

"@"符号的变量是实例变量,前面不带@,可以是常量,也可以是局部变量,也可以是全局变量。阅读Ruby Programming/Syntax/Variables and Constants

有时我会看到冒号在前面的变量,例如 :order

它们被称为符号

然后我看到冒号结尾的变量,例如冒号:。我不明白结肠在做什么。

这些可能是哈希语法(正如您给我们的提示,所以我猜),其中键是符号。示例:{foo: 1}- 这是一个哈希

另请按照您的要求阅读:

于 2013-11-04T15:20:54.273 回答
2

实例变量: ( @foo = '123') 定义了一个实例变量,并在整个请求的当前实例中保持其值。在 rails mvc 范例中,最常见的实例变量用于帮助将数据从控制器传递到视图,并允许您在控制器的一部分中定义事物并在另一部分中使用。

class ProjectsController < ApplicationController
  before_filter :find_project

  def show; end

  def update
    if @project.update_attributes(params[:project])
      ...
    end
  end

  private
  def find_project
    @project = Project.find(params[:id])
  end
end

在上面的代码中,您可以看到有一个 before 过滤器在每个方法之前运行。在上述情况下,我们找到当前项目并将其保存到实例变量中。并且因为它是一个实例方法,所以它可以在这个类中的任何地方访问,也可以访问用于呈现 html 的视图。

局部变量: ( foo = '123') 顾名思义,它们只能在def定义它们的当前方法 ( ) 中访问。

于 2013-11-04T15:33:17.333 回答