【问题标题】:What does Ruby constant mean?红宝石常数是什么意思?
【发布时间】:2009-12-30 00:25:44
【问题描述】:

Ruby 常量的真正含义是什么?以下代码未显示任何“常量”属性。警告在那里,但我仍然可以更改 A 所指的内容。

A = 1
puts A # => 1
A = 2  # warning: already initialized constant A
puts A # => 2

还是说 Ruby 常量只是一个指示,没有任何强制执行?

【问题讨论】:

    标签: ruby constants


    【解决方案1】:

    没错,constants 就像 ruby​​ 中的 variables,但是如果你改变它们,你会得到一个警告。

    此外,与单纯的变量有一个区别:您可以访问常量,即使它们是在另一个类或模块中定义的,例如给定这个 sn-p:

    module Constants
      PI = 3,1415
      other = "variable"
    end
    

    您可以通过Constants::PI 联系PI,而Constants::other 将不起作用。

    【讨论】:

    • 这个解释过于简单了。常量的查找规则与普通变量的查找规则完全不同,请参阅下面我的答案以获取解释此问题的博客文章的链接
    • 问题很简单,@bryantsai 正在寻找一个简单的答案。请注意,接受的答案比我的更简单
    • @Pablo,你的答案目前是公认的(看绿色勾号)——这就是我选择你的原因;)
    【解决方案2】:

    是的,除了打印警告外,没有强制使用 Ruby 常量。

    【讨论】:

      【解决方案3】:

      没错——赋值给一个常量是一个警告,而不是一个错误; “常量”只是指示您应该如何使用某些东西的指标,而不是您确实以这种方式使用它的规则。

      这在静态编程世界中听起来可能很可怕,但它在各种元编程工具中非常有用,它可以实现静态语言中完全不可能的事情。

      也就是说,如果您真的想确保人们不会对您的推荐信感到手足无措,您可以使用Object#freeze。用这个来改变参考指向的东西还是可以的;您只是无法更改引用本身的内容:

      irb(main):001:0> class Fruit; attr_accessor :name; end
      => nil
      irb(main):002:0> f = Fruit.new
      => #<Fruit:0xb7e06570>
      irb(main):003:0> f.name = "apple"
      => "apple"
      irb(main):004:0> f.freeze                # After freeze, can't touch this Fruit.
      => #<Fruit:0xb7e06570 @name="apple">
      irb(main):005:0> f.name = "banana"
      TypeError: can't modify frozen object    # Kablammo!
          from (irb):5:in `name='
          from (irb):5
      

      但这没关系:

      irb(main):006:0> f = Fruit.new
      => #<Fruit:0xb7dfed84>
      irb(main):007:0> f.name = "banana"
      => "banana"
      

      【讨论】:

      • 在您的示例中,constant 将是 Fruit。所以应该是Fruit.freeze 而不是f.freeze
      • 是的,但我认为 OP 隐含地询问如何在创建值后使其不可变。常量不会那样做。 freeze 可以(您可以在任何对象上使用freeze)。
      • 你不是说“给常量赋值是警告,而不是错误”吗?
      • 脏手会造成很大的伤害
      【解决方案4】:

      “常量”确实是用词不当,Ruby 的“常量”最重要的方面不是它们的不变性,而是它们的查找规则。

      见:http://coderrr.wordpress.com/2008/03/11/constant-name-resolution-in-ruby/

      【讨论】:

      • 看不到博客文章说“受保护的博客”。机器时也不在退路。
      • “coderrr.wordpress.com 不再可用。” “作者已经删除了这个网站。”这证明了链接到 SO 外部的信息而不在 SO 内部复制足够的相关信息并不是一个好主意。
      【解决方案5】:

      常量用于存储不应更改的值。他们的名字必须以大写字母开头。按照惯例,大多数常量名称都以大写字母书写,并带有下划线作为单词分隔符,例如 SOME_CONSTANT。

      类中定义的常量可以被该类的所有方法访问。在类之外创建的那些可以全局访问(在任何方法或类中)。

      class Car
        WHEELS = 4
      
        def initialize
          puts WHEELS
        end
      end
      
      c = Car.new     # Output: 4
      

      请注意,Ruby 不会阻止我们更改常量的值,它只会发出警告。

      SOME_CONSTANT = "foo"
      SOME_CONSTANT = "bar"
      warning: already initialized constant SOME_CONSTANT
      warning: previous definition of SOME_CONSTANT was here
      

      在 Ruby 中,所有类名和模块名都是常量,但约定要求它们应该用驼峰写法,例如 SomeClass。

      通过使用 ::(双冒号)运算符,可以从类外部访问常量,甚至在另一个类中。要从 Car 类外部访问 WHEELS 常量,我们将使用 Car::WHEELS。 :: 运算符允许从定义它们的类或模块外部访问常量、公共实例方法和类方法。

      名为 private_constant 的内置方法使常量成为私有的(只能在创建它们的类中访问)。语法如下:

      class Car
        WHEELS = 4
      
        private_constant:WHEELS
      end
      
      Car::WHEELS    # Output: NameError: private constant Car::WHEELS referenced
      

      【讨论】:

        【解决方案6】:

        如果您来自其他编程语言,Ruby 处理常量的方式与您可能习惯的方式不同。通常,常量采用在整个应用程序中不会改变的值。语法是在命名常量时使用所有大写字母,以便应用程序知道如何处理它。例如,要设置一个常量来容纳一支棒球队,您可以这样声明:

        TEAM = "Angels"
        

        我知道你知道这么多,请耐心等待。通常,其他编程语言不允许您更改 TEAM 的值。但是,Ruby 不会阻止您,它会获取分配给常量的最后一个值。在上面的示例中,我可以将其值更改为:

        TEAM = "Athletics"
        

        其他编程语言要么抛出错误,要么打印 Angels 的值。但是,Ruby 会打印出值 Athletics,因为这是分配给变量 TEAM 的最后一个值。此外,它会给出一条警告消息,指出该常量已经初始化并已更改,因为更改常量被认为是一种糟糕的编程习惯。但是,它仍然允许您进行更改并遵循相信开发人员做出正确编程决策的 Ruby 约定。因此,在 Ruby 中使用常量时要小心,因为它们可以被覆盖。

        【讨论】:

          猜你喜欢
          • 2010-10-06
          • 1970-01-01
          • 1970-01-01
          • 2015-07-14
          • 2012-08-27
          • 2014-10-22
          • 1970-01-01
          • 1970-01-01
          • 2011-09-09
          相关资源
          最近更新 更多