You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby读取YAML游戏存档无法访问Hangman实例变量值的问题

问题产生原因

报错的核心原因有两个:

  • 存档时你使用[] << self将Hangman实例包裹在数组中再序列化,因此YAML文件加载后的顶层结构是长度为1的数组,数组索引0位置的元素才是反序列化得到的Hangman对象,你直接对顶层数组调用键值访问方法必然出错。
  • YAML中的!ruby/object:Hangman是Ruby内置对象序列化的类型标记,加载该标记的内容时,YAML解析器会直接还原出Hangman类的实例对象,而非普通的键值对哈希结构,因此无法使用dig、[]等哈希专属的键访问方法读取内部实例变量。
    你调试时打印的输出已经验证了这点:yaml.class返回Array,yaml[0]才是带所有实例变量的Hangman实例。
修复方案

你可以选择以下任意一种方案修复:

方案1:仅修改读档逻辑,兼容现有存档格式

不需要重新生成存档,调整读档方法先取出数组内的Hangman实例,再读取实例变量赋值即可。注意Ruby 2.7+版本加载自定义类序列化的YAML时,需要显式声明允许加载的类,避免触发安全拦截。

# 先在Hangman类中开放实例变量访问权限(如果没加的话)
attr_accessor :secret_word, :secret_word_immutable, :secret_word_display,
              :guesses, :end_game, :wrong_letters_guessed, :right_letters_guessed

def load_game
  # 加载时声明允许反序列化Hangman类
  saved_array = YAML.load_file('saved_game.yml', permitted_classes: [Hangman])
  saved_game = saved_array[0] # 取出数组中存储的Hangman实例

  @secret_word = saved_game.secret_word
  @secret_word_immutable = saved_game.secret_word_immutable
  @secret_word_display = saved_game.secret_word_display
  @guesses = saved_game.guesses
  @end_game = saved_game.end_game
  @wrong_letters_guessed = saved_game.wrong_letters_guessed
  @right_letters_guessed = saved_game.right_letters_guessed
  puts "Saved game loaded!"
end

如果你不想添加attr_accessor,也可以直接用instance_variable_get方法读取实例变量,例如saved_game.instance_variable_get(:@secret_word)。

方案2:优化存档逻辑,去掉多余的数组包裹

从根源简化结构,修改存档方法直接序列化Hangman实例本身,不再套一层空数组:

def save_game
  File.open('saved_game.yml', 'w') { |f| YAML.dump(self, f) }
  puts 'Game Saved!'
end

对应读档方法不需要再取数组索引,直接读取加载后的对象即可:

def load_game
  saved_game = YAML.load_file('saved_game.yml', permitted_classes: [Hangman])
  @secret_word = saved_game.instance_variable_get(:@secret_word)
  @secret_word_immutable = saved_game.instance_variable_get(:@secret_word_immutable)
  @secret_word_display = saved_game.instance_variable_get(:@secret_word_display)
  @guesses = saved_game.instance_variable_get(:@guesses)
  @end_game = saved_game.instance_variable_get(:@end_game)
  @wrong_letters_guessed = saved_game.instance_variable_get(:@wrong_letters_guessed)
  @right_letters_guessed = saved_game.instance_variable_get(:@right_letters_guessed)
  puts "Saved game loaded!"
end

注意:如果使用Ruby 3.0及以上版本,省略permitted_classes参数会抛出Psych::DisallowedClass异常,这是YAML解析器的默认安全机制,防止恶意构造的YAML文件实例化危险类。

内容的提问来源于stack exchange,提问作者mikerachman1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 10:48:19