2012-06-25 46 views
0

为什么Ruby迫使我在局部变量而不是实例变量中实例化/存储这些类?Ruby正在本地变量中存储类而不是实例变量

之前,我改变了我的代码,使其功能,我有这样的:

require 'test/unit' 
require 'converter' 

class TestConverter < Test::Unit::TestCase 

    @cv = Convert.new 

    def test_celsius 
    assert_equal(100.0, @cv.celsius(212)) 
    assert_equal(0.0, @[email protected](32)) 
    end 

    def test_fahrenheit 
    assert_equal(212.0, @cv.fahrenheit(100)) 
    assert_equal(32.0, @cv.fahrenheit(0)) 
    end 

end 

其抛出这个错误:

% ruby -I. converter_test.rb             ✭ 
Run options: 

# Running tests: 

EE 

Finished tests in 0.000616s, 3246.7638 tests/s, 0.0000 assertions/s. 

    1) Error: 
test_celsius(TestConverter): 
NoMethodError: undefined method `celsius' for nil:NilClass 
    converter_test.rb:9:in `test_celsius' 

    2) Error: 
test_fahrenheit(TestConverter): 
NoMethodError: undefined method `fahrenheit' for nil:NilClass 
    converter_test.rb:14:in `test_fahrenheit' 

2 tests, 0 assertions, 0 failures, 2 errors, 0 skips 

我决定尝试实例每个内部类(转换)方法并且成功:

require 'test/unit' 
require 'converter' 

class TestConverter < Test::Unit::TestCase 

    #@cv = Convert.new 
    #instantiated the class in each method instead of here 

    def test_celsius 
    cv = Convert.new 
    assert_equal(100.0, cv.celsius(212)) 
    assert_equal(0, cv.celsius(32)) 
    end 

    def test_fahrenheit 
    cv = Convert.new 
    assert_equal(212, cv.fahrenheit(100)) 
assert_equal(32, cv.fahrenheit(0)) 
end 
end 
[email protected]:~/Develop/davincicoders$ ruby -I. converter_test.rb 
Run options: 

# Running tests: 

.. 

Finished tests in 0.001894s, 1055.9149 tests/s, 2111.8298 assertions/s. 

2 tests, 4 assertions, 0 failures, 0 errors, 0 skips 

为什么Ruby不能识别实例变量为第一次尝试中的对象?

+0

因为这不是你在Ruby中声明实例变量的方式。在类声明中,你在类中,而不是一个实例,所以@variable不是你所相信的。 –

+1

所以基本上它没有工作,因为我定义了方法外的实例。如果我在初始化方法中完成了它,它会起作用。对?嗯....在测试中,这似乎并没有工作......好吧,我想我明白了。多谢你们。 –

+0

哪一个会是最有效的代码?使用@@ class_var声明或以我上面所做的方式进行操作? –

回答

3

声明@cv测试之外,使其成为TestConverter实例变量 - 不是TestConverter一个实例!

可能最容易的方法是让它变成一个类变量:@@cv

如果你还在迷茫,考虑这个例子:

class Foo 
    @x = 3 
    def initialize 
    @y = 4 
    end 
end 

puts Foo.instance_variables 
puts Foo.new.instance_variables 
+0

呵呵。我会冥想这件事。 –

0
assert_equal(0.0, @[email protected](32)) 

不应该这个是

assert_equal(0.0, @cv.celsius(32)) 
+0

是的,如果它实际上是一个实例变量......但它不是OP相信它的实例变量。最终,这并不能回答真正的问题,这是对Ruby的误解。 –

+0

什么是OP? –

+0

@大卫“OP”的意思是“原创海报”。这是一个性别不可知且简短的方式来提及问问题的人。 – Phrogz

2

这经常混淆的人(包括我),因为它的工作原理不同于你会从其他语言的期望。我会尝试用一个Java的例子来说明:

class Foo 
    @bar = 42 
end 

相当于

public class Foo { 
     private int bar = 42; 
} 

但实际上大致相当于

public class Foo { 
     private static int bar = 42; 
} 

尝试一下在你的IRB:

class Foo 
    attr_accessor :bar 
    @bar = 42 
    class << self 
    attr_accessor :bar 
    end 
end 
Foo.bar # => 42 
Foo.new.bar # => nil 

那么这是为什么呢?在Ruby中,一切都是一个对象!因此,任何类别(例如Foo)都是Class类别的一个实例(听起来令人困惑,我知道)。 class Foo; end之间的任何内容都在Class类的实例Foo的范围内执行。

这绝不是一个完整的解释,所以你应该真正阅读细节。