You need to enable JavaScript to run this app. Ruby中使用attr_accessor定义的实例变量外部访问为nil且报未定义方法错误
优惠活动
大模型
产品
解决方案
定价
更多

Ruby中使用attr_accessor定义的实例变量外部访问为nil且报未定义方法错误

问题根因与面向对象封装逻辑解析

直接触发报错的表层原因

NoMethodError: undefined method 'has_key?' for nil:NilClass 本质是执行cur.children.has_key? char时,cur.children的返回值为nil,而nil本身没有has_key?方法,因此抛出错误。

深层根因拆解

1. 初始化方法拼写错误,实例变量从未完成赋值

Ruby中类的实例初始化钩子方法是固定拼写的initialize,类方法new的执行逻辑是:先为新实例分配内存空间,随后自动调用该实例的initialize方法完成初始化。
你在TrieNode中写的方法名是initalize(漏写了一个字母i),这个方法只会作为普通的自定义实例方法存在,完全不会在执行TrieNode.new时被自动调用。
这就导致你写在该方法里的@children = Hash.new这类赋值逻辑全程没有执行,所有TrieNode实例的@children、@value、@next实例变量从未被显式赋值。Ruby语言设计中,读取未显式赋值的实例变量会直接返回nil,不会抛出未定义实例变量的错误,只有当你对这个nil调用不存在的方法时,才会触发NoMethodError。

2. 对attr系列宏的封装逻辑存在误解

你使用attr_reader、attr_accessor的初衷是封装实例变量的访问权限,但这类宏的作用仅为自动生成对外的访问接口方法,并不会帮你初始化实例变量:

  • attr_reader :children 等价于手写def children; @children; end,仅暴露读取@children的接口
  • attr_accessor :root 等价于同时生成def root; @root; end和def root=(val); @root = val; end读写两个接口
  • 无论使用哪种attr宏,都需要你在实例生命周期的合适节点(通常是initialize方法)给对应的实例变量赋值,否则接口返回的结果永远是nil。

修正后的可运行代码

class TrieNode
  attr_reader :value, :next, :children

  # 修正方法拼写为标准初始化方法名
  def initialize
    @value = nil
    @children = Hash.new
    @next = nil
  end
end

class Trie
  attr_accessor :root

  def initialize
    @root = TrieNode.new
  end

  def build_trie(strs)
    cur = @root
    strs.each do |str|
      str.chars.each do |char|
        if cur.children.has_key?(char)
          cur = cur.children[char]
          next
        else
          new_node = TrieNode.new
          cur.children[char] = new_node
          cur = new_node
        end
      end
      cur = @root
    end
  end
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 12:06:07