Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在没有警告的情况下重新定义Ruby常量?_Ruby_Constants_Redefine_Redefinition - Fatal编程技术网

如何在没有警告的情况下重新定义Ruby常量?

如何在没有警告的情况下重新定义Ruby常量?,ruby,constants,redefine,redefinition,Ruby,Constants,Redefine,Redefinition,我正在运行一些Ruby代码,每当Ruby文件的日期发生变化时,都会对其进行求值。在文件中,我有常量定义,如 Tau = 2 * Pi 当然,它们会让解释器每次都显示不需要的“已初始化常量”警告,因此,我希望有以下功能: def_if_not_defined(:Tau, 2 * Pi) redef_without_warning(:Tau, 2 * Pi) 我可以这样写我所有的常量定义来避免警告: Tau = 2 * Pi unless defined?(Tau) 但它不雅观,而且有点湿(不

我正在运行一些Ruby代码,每当Ruby文件的日期发生变化时,都会对其进行求值。在文件中,我有常量定义,如

Tau = 2 * Pi
当然,它们会让解释器每次都显示不需要的“已初始化常量”警告,因此,我希望有以下功能:

def_if_not_defined(:Tau, 2 * Pi)
redef_without_warning(:Tau, 2 * Pi)
我可以这样写我所有的常量定义来避免警告:

Tau = 2 * Pi unless defined?(Tau)
但它不雅观,而且有点湿(不湿)

如果未定义,是否有更好的方法定义?以及如何在没有警告的情况下重新定义

--

感谢Steve的解决方案:

class Object
  def def_if_not_defined(const, value)
    mod = self.is_a?(Module) ? self : self.class
    mod.const_set(const, value) unless mod.const_defined?(const)
  end

  def redef_without_warning(const, value)
    mod = self.is_a?(Module) ? self : self.class
    mod.send(:remove_const, const) if mod.const_defined?(const)
    mod.const_set(const, value)
  end
end

A = 1
redef_without_warning :A, 2
fail 'unit test' unless A == 2
module M
  B = 10
  redef_without_warning :B, 20
end
fail 'unit test' unless M::B == 20
--


这个问题由来已久。以上代码仅适用于Ruby 1.8。在Ruby 1.9中,P3t3rU5的答案不会产生任何警告,只是更好。

如果您想重新定义一个值,那么不要使用常量,而是使用一个全局变量($tau=2*Pi),但这也不是一个好的做法。您应该使其成为合适类的实例变量


对于另一种情况,
Tau=2*Pi,除非定义?(Tau)
完全正确,可读性最好,因此是最优雅的解决方案。

除非常数的值非常奇怪(即,将常数设置为
nil
false
),最好的选择是使用条件赋值运算符:
Tau | |=2*Pi


如果Tau为
nil
false
或未定义,则将其设置为2π,否则将不进行设置。

以下模块可能会执行您想要的操作。如果没有,它可能会为您的解决方案提供一些指针

module RemovableConstants

  def def_if_not_defined(const, value)
    self.class.const_set(const, value) unless self.class.const_defined?(const)
  end

  def redef_without_warning(const, value)
    self.class.send(:remove_const, const) if self.class.const_defined?(const)
    self.class.const_set(const, value)
  end
end
作为使用它的一个例子

class A
  include RemovableConstants

  def initialize
    def_if_not_defined("Foo", "ABC")
    def_if_not_defined("Bar", "DEF")
  end

  def show_constants
    puts "Foo is #{Foo}"
    puts "Bar is #{Bar}"
  end

  def reload
    redef_without_warning("Foo", "GHI")
    redef_without_warning("Bar", "JKL")
  end

end

a = A.new
a.show_constants
a.reload
a.show_constants
给出以下输出

Foo is ABC
Bar is DEF
Foo is GHI
Bar is JKL

如果我在这里打破了ruby的禁忌,请原谅,因为我仍然在关注ruby中的一些模块:Class:Eigenclass结构,这里讨论了另一种使用$VERBOSE来抑制警告的方法:

更新2020/5/6:针对链接现在已经失效的评论,我在这里粘贴了一个来自我的旧项目的示例,尽管我不能说这是否是一个好方法,在什么情况下是一个好方法:

original_verbose = $VERBOSE
$VERBOSE = nil # suppress warnings
# do stuff that raises warnings you don't care about
$VERBOSE = original_verbose

为什么要重新定义常量?最好将常量保留在自己的类或模块中,这样它们就不会与其他常量冲突。我想重新定义常量,因为我想自然地使用常量,就像我没有使用自动源代码重新加载程序一样,所以我不会接受任何“只是不使用常量”回答。
Tau=2*Pi的不雅和不干涩之处,除非定义?(Tau)
?“Tau”写了两次。这没什么大不了的,除非名字很长或者不小心被重命名了。但是我更喜欢'redef:Tau,2*Pi',我目前正在编写RubyonRails教程的第二版,我在谷歌搜索解决过程中遇到的Ruby问题时发现了这个线程。事实证明,这并没有解决我所面临的确切问题,但我要说的是,由于我也是Tau宣言的作者,这让我非常高兴。:-)好主意。。。不幸的是,它的可移植性不强:根据ruby版本和实现(ruby/jruby),使用| |=对常量进行矫揉造作会产生三种不同的结果。要么它像预期的那样安静地工作(jruby1.5),要么我得到一个“未初始化常量”失败(ruby1.8),要么我得到一个警告,即使没有做作(jruby1.2)。是的。正如您在链接中提到的,Rails中有一个更好的静默警告实现:但这种方法不如公认的答案,因为它可能会对其他线程产生副作用。而且,该链接现在已经失效。当然,这个答案的关键是首先调用
Object.send(:remove_const,'Tau'),如果Object.const_已定义('Tau'))
,它取消对常量的定义,从而抢占警告。很好的方法。是的,或者只要
发送(:remove\u const,:const),如果定义了const?(:const)
如果您在类(而不是实例)范围内。