【问题标题】:Constants and scope in loops with RubyRuby 循环中的常量和范围
【发布时间】:2011-07-31 12:08:01
【问题描述】:

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

在 C++ 中这是可能的:

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

虽然尝试在循环期间更改值是不可能的,但会导致编译时错误。

我很好奇 Ruby 将如何处理这个问题,启动了 irb 并编写了这段代码来测试它:

5.times do |x|
  XPI = x * Math::PI
  puts x
end

结果是

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 scope constants


    【解决方案1】:

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

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

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

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

    但是,当您尝试更改冻结的对象时,Object#freeze 方法会导致出现异常:

    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>'
    

    因此,简而言之,使用CONSTANTS 会阻止(但不会阻止)重新分配,而冻结对象会阻止突变。这些都不能帮助你,因为冻结数字没有任何意义,因为它们已经是不可变的。

    【讨论】:

      【解决方案2】:

      在 ruby​​ 中似乎没有严格等同于 Java 的 final。但是,您可以使用remove_const(这是Module 中的私有方法)来消除循环末尾的常量(和警告):

      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
      

      【讨论】:

        【解决方案3】:

        我认为常量不适用于此。毕竟,您使用名称来引用不同的值。真正的 CONSTANT 将在程序的整个生命周期中保持不变。至少,这是使用全大写名称的惯例。

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

        您所拥有的只是一个局部变量,恰好在循环开始时计算一次。你应该给它一个普通的名字。如果你想确保它不会改变,你需要在编码时注意,编写测试来验证循环是否符合你的预期,并且可能需要有人审查代码。

        【讨论】:

        • 我认为你是对的,它不符合 Ruby 哲学。虽然我认为它不仅仅是一个局部变量。我认为在强类型上下文中,这种“合同”的可靠性不会在特定范围内更改变量内容是有道理的。
        猜你喜欢
        • 2013-06-12
        • 2011-02-10
        • 2023-03-31
        • 2013-11-18
        • 2013-08-30
        • 1970-01-01
        • 2018-04-25
        • 1970-01-01
        相关资源
        最近更新 更多