繁体   English   中英

`const_missing': 未初始化的常量 (NameError) - 需要

[英]`const_missing': uninitialized constant (NameError) - Require

我在执行代码时收到 `const_missing': uninitialized constant Disc::Foo1 (NameError)

光盘.rb

module Disc
  MAPPING = {
  :new => {
    :first => Foo1,
    :second => Foo2
  },
  :old => {
    :third => Foo3,
    :fourth => Foo4
  }

  def run
    # :new and :first is example but will be any value decided based on the logic dynamically.
    cls = MAPPING[:new][:first]
    cls.new.execute
  end
}
end

foo1.rb

class Foo1
  def initialize
  end

  def execute
    puts "f1"
  end
end

foo2.rb

class Foo2
  def initialize
  end

  def execute
    puts "f2"
  end
end

foo3.rb

class Foo3
  def initialize
  end

  def execute
    puts "f3"
  end
end

foo4.rb

class Foo4
  def initialize
  end

  def execute
    puts "f4"
  end
end

我是 ruby 的新手。 我试图找到解决方案,发现我必须添加require子句并尝试了很多东西但没有奏效。 有人可以帮我吗?

Ruby 不能自动加载文件——你需要明确告诉它加载它们。 只需坐在同一个目录中,他们就不会做任何事情。 这是因为,与其他一些语言不同,文件名与其内容之间没有可预测的集合映射,因此 Ruby 无法知道您想要的 class 在哪里。 你必须

require './foo1'
require './foo2'
require './foo3'
require './foo4'

或者,你可以做得更聪明一点:

%w(./foo1 ./foo2 ./foo3 ./foo4).each do |file|
  require file
end

现在您知道了require ... 说 Ruby 不能自动加载文件是告诉 Ruby 新手的谎言。 Ruby 可以完全自动加载文件。 但是您仍然必须告诉它它们是什么以及在哪里可以找到它们。 只需坐在同一个目录中,他们就不会做任何事情。 你必须

autoload(:Foo1, './foo1.rb')
autoload(:Foo2, './foo2.rb')
autoload(:Foo3, './foo3.rb')
autoload(:Foo4, './foo4.rb')

除非您尝试访问命名类,否则不会加载文件; 当你这样做时,Ruby 会记住你告诉它在哪里找到这些类,并加载相应的文件。 这样可以节省程序启动时间和 memory,因为只会加载实际需要的文件。

您也可以这样做:

# for each `./foo*.rb` file
Dir.glob('./foo*.rb').each do |file|
  # turn it into the class name; e.g. `./foo1.rb' -> :Foo1
  classname = file[%r{\./(.*)\.rb$}, 1].capitalize.to_sym
  # then tell Ruby that that classname can be found in that file
  autoload(classname, file)
end

但是,由于您在MAPPING中明确包含类,因此自动加载对您没有帮助 - 所有 foo 文件都将在定义MAPPING时自动加载,因此在此处使用autoload没有任何好处。 如果您存储名称而不是 class 对象本身,并使用Object.const_get查找 class ZA8CFDE 常量,那么 8931BD59EB62ACZ6 将起作用:

autoload(:Foo1, './foo1.rb')
# `./foo1.rb` is not yet loaded

MAPPING = {
  new: {
    first: :Foo1,
    # ...
  },
  # ...
}
# `./foo1.rb` is still not loaded:
# we haven't used the `Foo1` constant yet
# (we did use `:Foo1` symbol, but that is a completely different thing)

cls = Object.const_get(MAPPING[:new][:first])
# `./foo1.rb` is now loaded, and `cls` is `Foo1`

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM