【问题标题】:Class variable access from top level从顶层访问类变量
【发布时间】:2015-09-27 03:53:52
【问题描述】:

我完全是 Ruby 的初学者。我目前正在学习艰难地学习 Ruby 的第 45 课,并且正在创建一个类似于 Zork 和 Adventure 的游戏。

我创建了一个结构,我在不同的文件中创建“场景”,并要求一个文件中的所有场景,其中我有一个引擎/地图,以确保当前场景不等于“完成”它运行“X” ' 场景的 'enter' 方法。

但是我有两个问题: 1) 我不断收到一条错误消息,提示“警告从顶层访问类变量” 2)即使脚本正在运行,我也得到了

ex45.rb:30:in `play': undefined method `enter' for nil:NilClass (NoMethodError) from ex45.rb:59:in

以下是我每个文件中的所有代码。如果阅读时间很长,我深表歉意,但我很想知道为什么会出现这两个错误以及我能做些什么来解决它们。

Ex45.rb:

require "./scene_one.rb"
require "./scene_two.rb"
require "./scene_three.rb"

@@action = SceneOne.new
@@action_two = SceneTwo.new
@@action_three = SceneThree.new

class Engine

    def initialize(scene_map)
        @scene_map = scene_map
    end

    def play()      
        current_scene = @scene_map.opening_scene()
        last_scene = @scene_map.next_scene('finished')

        while current_scene != last_scene
            next_scene_name = current_scene.enter()
            current_scene = @scene_map.next_scene(next_scene_name)
        end

        current_scene.enter()
    end
end


class Map

    @@scenes = {
        'scene_one' => @@action,
        'scene_two' => @@action_two,
        'scene_three' => @@action_three
    }

    def initialize(start_scene)
        @start_scene = start_scene
    end

    def next_scene(scene_name)
        val = @@scenes[scene_name]
        return val
    end

    def opening_scene()
        return next_scene(@start_scene)
    end
end

a_map = Map.new('scene_one')
a_game = Engine.new(a_map)
a_game.play()

scene_one.rb:

类 SceneOne

  def enter
    puts "What is 1 + 2?"
    print "> "

    answer = $stdin.gets.chomp

    if answer == "3"
        puts "Good job"
        return 'scene_two'
    else
        puts "try again"
        test
    end
  end

end

scene_two.rb

class SceneTwo

    def enter
        puts "1 + 3?"
        print "> "

        action = $stdin.gets.chomp

        if action == "4"
            return 'scene_three'
        else
            puts "CANNOT COMPUTE"
        end
    end

end

scene_three.rb

class SceneThree

    def enter
        puts "This is scene three"
    end

end

提前致谢!

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

    回答您的第一个问题

    您需要在 Map 类中移动类变量定义以消除这些警告:

    Ex45.rb:5: warning: class variable access from toplevel
    Ex45.rb:6: warning: class variable access from toplevel
    Ex45.rb:7: warning: class variable access from toplevel
    

    所以,你的 Map 类应该是这样的:

    class Map
        @@action = SceneOne.new
        @@action_two = SceneTwo.new
        @@action_three = SceneThree.new
    
        @@scenes = {
            'scene_one' => @@action,
            'scene_two' => @@action_two,
            'scene_three' => @@action_three
        }
    
        def initialize(start_scene)
            @start_scene = start_scene
        end
    
        def next_scene(scene_name)
            val = @@scenes[scene_name]
            return val
        end
    
        def opening_scene()
            return next_scene(@start_scene)
        end
    end
    

    回答你的第二个问题:

    您收到undefined method 'enter' for nil:NilClass (NoMethodError) 是因为您的current_scene 在某个时刻变为nil,然后您尝试调用:current_scene.enter()nil.enter,但它失败并显示该错误消息。

    要解决此问题,您必须确保您的 current_scene 始终具有一些价值,即确保它不是 nil

    我认为,您可以从 Engine 类中的 play 方法的末尾删除 current_scene.enter() 行。因此,您的 Engine 类将如下所示:

    class Engine
        def initialize(scene_map)
            @scene_map = scene_map
        end
    
        def play()      
            current_scene = @scene_map.opening_scene()
            last_scene = @scene_map.next_scene('finished')
    
            while current_scene != last_scene
                next_scene_name = current_scene.enter()
                current_scene = @scene_map.next_scene(next_scene_name)
            end
    
            # current_scene.enter()
        end
    end
    

    而且,您不会再收到该错误。

    【讨论】:

    • 会不会是这条线? @scene_map.opening_scene() 它是从 Engine 类中的 play 函数调用的,但 opening_scene() 是在 Map 类中定义的。但我对 @ 或 @@ 变量的事情不是很清楚
    • 不,这不是问题,因为@scene_mapMap 类的对象。所以,没关系。问题是,current_sceneplay 类的play 方法的while 循环末尾是nil,正如我在答案的第二部分中指定的那样。
    • 非常感谢您的帮助!两种解决方案都有效!我还记得我有一个while循环,我在其中说明当前场景!=最后一个场景(即“完成”)。所以这种方式'current_scene'要么基本上等于scene_map.opening_scene要么'finished'。因此,一旦我添加了“完成”文件并且 current_scene 不能 = nil,我就停止了错误。再次感谢!
    • @KarthikSoravanahalli 很高兴它帮助您解决了问题 :)
    • @KMRakibulIslam 陷阱。这就是为什么我问的比试图回答的要多,大声笑。你已经得到了我的 +1 ;)
    【解决方案2】:

    让你知道:

    @@y = 20
    p Object.class_variables
    
    --output:--
    1.rb:1: warning: class variable access from toplevel
    [:@@y]
    

    还有:

    class Object
      def self.y
        @@y
      end
    end
    
    puts Object.y
    
    --output:--
    20
    

    但是:

    class Dog
      @@y = "hello"
    
      def self.y
        @@y
      end
    end
    
    puts Dog.y     #=>hello
    puts Object.y  #=>What do you think?
    

    最后一行的输出是 ruby​​ 中不使用类变量的原因。您应该使用所谓的类实例变量,而不是类变量

    class Object
      @y = 10   #class instance variable
    
      def self.y
        @y
      end
    end
    
    puts Object.y
    
    
    class Dog
      @y = "hello"
    
      def self.y
        @y
      end
    end
    
    puts Dog.y     #=> hello
    puts Object.y  #=> 10
    

    类实例变量只是类内部的@variable,但在任何定义之外。而不是所有子类共享一个 @@variable,每个子类将有自己的 @variable

    【讨论】:

      猜你喜欢
      • 2011-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-22
      • 2013-01-16
      • 1970-01-01
      • 1970-01-01
      • 2011-06-15
      相关资源
      最近更新 更多