Ruby循环中的常量和作用域

Ruby循环中的常量和作用域,ruby,scope,constants,Ruby,Scope,Constants,在这个问题中,我发现了一个关于Java中final变量范围的有趣细节。我对Java不够了解,但我认为final与Ruby中的常量相同 在C++中,这是可能的: for(int i = 0; i < 5; ++i){ const int c = i * 5; std::cout << c << std::endl; } 结果是 0.0 (irb):27: warning: already initialized constant XPI 3.1415

在这个问题中,我发现了一个关于Java中
final
变量范围的有趣细节。我对Java不够了解,但我认为
final
与Ruby中的常量相同

在C++中,这是可能的:

for(int i = 0; i < 5; ++i){
    const int c = i * 5;
    std::cout << c << std::endl;
}
结果是

0.0
(irb):27: warning: already initialized constant XPI
3.141592653589793
(irb):27: warning: already initialized constant XPI
6.283185307179586
(irb):27: warning: already initialized constant XPI
9.42477796076938
(irb):27: warning: already initialized constant XPI
12.566370614359172
=> 5
所以我的问题是:有没有一种方法可以在循环的开始处分配一个常量,该常量在每次循环迭代时都会被初始化,而不会产生警告消息?它可能有一些真实的用例,当我想基于迭代器变量进行计算,然后确保剩余循环的结果不会改变


你每天都不需要什么,但我只是好奇。

在ruby中似乎没有严格等同于Java的最终版本。但是,您可以使用(这是
模块
中的私有方法)删除循环末尾的常量(和警告):

5.times do |x| 
  XPI = x * Math::PI; 
  puts x; 
  Object.instance_eval{ remove_const :XPI };
  # this would work, too: Object.send(:remove_const, :XPI); 
end

简言之,没有。但是有几件事你应该注意

常量
,正如您已经看到的,并不是常量。他们可以重新分配,只需一个警告。此外,不能在方法中指定常量

但更重要的是,它们不会对其持有的对象施加任何影响:即使没有警告,也可以毫无问题地对对象进行变异:

STRING_CONST = 'foo'
#=>'foo'
STRING_CONST << 'bar'
#=>'foobar'

因此,简而言之,使用
常量
不鼓励(但不阻止)重新分配,冻结对象可以防止变异。这两个都不能帮助你,因为冻结的数字没有意义,因为它们已经是不可变的。

我认为常数不适合于此。毕竟,您使用该名称来连续引用不同的值。在程序的整个生命周期中,真常量都是常量。至少,这是使用完全大写的名称的惯例

在某些语言中,您可以确保(有时是默认情况下)值不会更改。Ruby不是这样一种语言。即使是真正的常数也可以改变


您所拥有的只是一个局部变量,它恰好在循环开始时计算一次。你应该给它起个固定的名字。如果您想确保它不会改变,那么在编写代码时需要注意,编写测试以验证循环是否符合您的预期,或者让人检查代码。

我认为您是对的,它不符合Ruby的理念。虽然我认为它不仅仅是一个局部变量。我认为在强类型上下文中,这种“契约”的可靠性在一定范围内不改变变量内容是有意义的。
STRING_CONST = 'foo'
#=>'foo'
STRING_CONST << 'bar'
#=>'foobar'
CONST_STRING = 'foo'
#=> "foo"
CONST_STRING.freeze
CONST_STRING << 'bar'
RuntimeError: can't modify frozen string
    from (irb):12
    from /usr/bin/irb:12:in `<main>'