【问题标题】:How to properly access instance variables in one inner-class from another inner-class?如何从另一个内部类正确访问一个内部类中的实例变量?
【发布时间】:2025-12-14 17:50:01
【问题描述】:

我正在创建一个井字游戏。我是 ruby​​ 新手,并且定义了一个类 Game,有两个内部类 PlayerGameBoard。在Game 中,我定义了两个实例变量player1player2。我正在尝试访问方法GameBoard.update_gameboard 中的player1player2,就像这样

def update_gameboard(player)
      move = if player == 1
               @player1.moves[@player1.turn]
             else
               @player2.moves[@player2.turn]
             end
.
.
.

我得到了错误:

/Users/Jacob/Development/RubyDev/RubymineProjects/TicTacToe/tictactoe.rb:85:in `update_gameboard': undefined method `moves' for nil:NilClass (NoMethodError)
    from /Users/Jacob/Development/RubyDev/RubymineProjects/TicTacToe/tictactoe.rb:44:in `play'
    from /Users/Jacob/Development/RubyDev/RubymineProjects/TicTacTOe/main.rb:30:in `<top (required)>'
    from -e:1:in `load'
    from -e:1:in `<main>'

Process finished with exit code 1

moves 不是一个方法,它是一个数组。 (playGame 中的一个方法,它调用update_gameboard

如何从内部类(例如GameBoard)访问外部类(Game)的实例变量?

class Game
  attr_accessor :winner, :player1, :player2, :gameboard

  def initialize(player1_name, player2_name)
    @player1 = Player.new(player1_name, 'X')
    @player2 = Player.new(player2_name, 'O')
    @gameboard = GameBoard.new
  end
.
.
.
  class GameBoard
    attr_accessor :current_gameboard
    attr_reader :gameboard_move_map

    def initialize
          # initialize irrelevant GameBoard variables
    end

    def update_gameboard(player)
      move = if player == 1
               @player1.moves[@player1.turn]
             else
               @player2.moves[@player2.turn]
             end
      #then some more stuff that uses @player1 and @player2
    end
.
.
.
  end
end



【问题讨论】:

  • @IshaanJavali 我看到了这个问题。对于这种情况,它对我没有帮助。
  • 这可能是因为我在 OOP 方面没有受过足够的教育,无法理解如何将这些实例应用到我在 ruby​​ 中的工作中。

标签: ruby inner-classes


【解决方案1】:

这里非常重要的概念。 “内部课程”并没有做你认为的那样。除了命名空间之外,这两个类之间绝对没有关系或特殊行为。基本上,只需将内部类视为完全独立定义的,因为这就是它的行为方式。

不过,您可以做的一件事是向 GameBoard 构造函数传递对 Game 实例的引用,这样您就可以访问实例变量:

(请注意,我只显示与答案相关的部分,为了简洁起见,我省略了代码的其他部分):

class GameBoard
  attr_reader :game
  def initialize(game)
    @game = game
  end
end

class Game
  def initialize(player1_name, player2_name)
    @player1 = Player.new(player1_name, 'X')
    @player2 = Player.new(player2_name, 'O')

    # Note I pass the Game instance as self here:
    @gameboard = GameBoard.new(self)
  end
end

然后在GameBoard 实例方法中,您可以执行以下操作:

game.player1.moves[game.player1.turn]

game这里是attr_reader生成的方法(参考initialize中设置的@game实例变量)。

【讨论】:

  • 太棒了。真的很棒的答案。