【问题标题】:Ruby Instance Variables or Local Variables?Ruby 实例变量还是局部变量?
【发布时间】:2014-05-03 00:05:25
【问题描述】:

我是 Ruby 语言的新手。我明白了

@@count: Class variables
@name: Instance variables
my_string: Local variables

我牢记上述内容。但是,我发现了一个这样的 Ruby 代码:

class HBaseController < ApplicationController
...
  def result
    conn = OkHbase::Connection.new(host: 'localhost', port: 9090, auto_connect: true)
  ...
  end
end

'conn' 让我很困惑。

'conn' 是实例变量还是局部变量? 'conn'的范围是什么?

【问题讨论】:

  • 您似乎回答了自己的问题。 conn 的哪些方面让你认为它不是局部变量?
  • 因为这个变量在一个实例中。似乎实例中的局部变量和实例变量具有相同的范围,存在于实例的范围内,如果我将'conn'更改为'@conn'有什么区别?或者我的问题可能是什么区别是在实例中的局部变量和实例变量之间?

标签: ruby scope instance


【解决方案1】:

我试着用一个小例子来解释一下:

class MyClass
  def meth
    conn = 1
  end
  def result
    conn
  end
end

x = MyClass.new
p x.result #-> test.rb:6:in `result': undefined local variable or method `conn'

conn 未知。让我们尝试调用meth之前:

class MyClass
  def meth
    conn = 1
  end
  def result
    conn
  end
end

x = MyClass.new
x.meth      # try to create conn
p x.result  #-> test.rb:6:in `result': undefined local variable or method `conn' 

同样的结果。所以conn 不是实例变量。您在meth 中定义了一个局部变量,但它在外部是未知的。

让我们对实例变量进行同样的尝试:

class MyClass
  def meth
    @conn = 1
  end
  def result
    @conn
  end
end

x = MyClass.new
p x.result  #-> nil (no value assigned (*), but is is existing)
x.meth      # initialze @conn with a value
p x.result  #-> 1

使用访问器方法,您可以隐式定义一个实例变量:

class MyClass
  attr_reader :conn
  def meth
    conn = 1
  end
  def result
    conn
  end
end

x = MyClass.new
p x.result  #-> nil (no value assigned (*), but is is existing)
x.meth      #   define conn with a value
p x.result  #-> nil - the instance variable is not changed, a locale variable was used

在方法result 中,conn 是读取器方法conn。在 meth 方法中,它是一个语言环境变量(这可能会让人感到困惑,因为现在您有了一个与变量同名的变量。

如果您想更改meth-方法中的conn-值,您必须定义一个setter并使用self.conn

class MyClass
  attr_reader :conn
  attr_writer :conn
  def meth
    self.conn = 1
  end
  def result
    conn
  end
end

x = MyClass.new
p x.result  #-> nil (not defined yet, but is is existing)
x.meth      #   define conn with a value
p x.result  #-> 1

您可以将attr_readerattr_writer 替换为attr_accessor

(*) 备注:我写的是no value assignment - 这不太正确,nil 也是一个值。

【讨论】:

  • 如果明确写出 getter 和 setter 方法,访问器示例可能会更加清晰,让您可以看到实例变量而不是隐藏在访问器内部。
  • @jstim:我修改了我的例子。
  • 我正在考虑明确地编写它们。我编辑了它,但可以随意回滚。
【解决方案2】:

conn是局部变量(局部变量以小写字母或下划线开头)

它包含一个 OkHbase::Connection 的实例

大概... 被省略的代码使用了那个对象。因为是局部变量,一旦result方法结束,局部变量将无法访问,对象会从内存中清除。

(当然,有可能省略的代码将conn 中的对象分配给实例变量或将其传递给已将其存储在其他地方的其他方法)

【讨论】:

    【解决方案3】:

    在这种情况下,conn 是局部变量。

    编辑:

    conn 将是一个实例变量,如果你把它写成这样

    @conn = OkHbase::Connection.new(host: 'localhost', port: 9090, auto_connect: true)

    【讨论】:

      【解决方案4】:

      conn 是方法 result 的本地对象

      块创建一个新的范围,方法和类声明也是如此。有趣的是,if 语句不会创建新的本地范围,因此您在 if 语句中声明的变量在外部可用。

      $ irb
      1.9.3-p484 :001 > if true
      1.9.3-p484 :002?>   foo = 1
      1.9.3-p484 :003?>   end
       => 1 
      1.9.3-p484 :004 > foo
       => 1 
      1.9.3-p484 :005 > 1.times do
      1.9.3-p484 :006 >     bar = 1
      1.9.3-p484 :007?>   end
       => 1 
      1.9.3-p484 :008 > bar
      NameError: undefined local variable or method `bar' for main:Object
          from (irb):8
          from irb:12:in `<main>'
      

      【讨论】:

        猜你喜欢
        • 2015-04-29
        • 2016-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多