0

为什么 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, @cv.@celsius(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

我决定尝试在每个方法中实例化类(Convert)并成功:

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
ddouglas@coders:~/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 在第一次尝试时不会将实例变量识别为对象?

4

3 回答 3

3

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

可能最简单的解决方法是将其设为类变量:@@cv.

如果您仍然感到困惑,请考虑以下示例:

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

puts Foo.instance_variables
puts Foo.new.instance_variables
于 2012-06-25T21:47:45.700 回答
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的实例范围内执行。FooClass

这绝不是一个完整的解释,因此您应该真正阅读详细信息。

于 2012-06-25T22:11:37.320 回答
0
assert_equal(0.0, @cv.@celsius(32))

这不应该是

assert_equal(0.0, @cv.celsius(32))
于 2012-06-25T21:42:15.967 回答