代码之家  ›  专栏  ›  技术社区  ›  aronchick

Ruby中的常量赋值错误?

  •  2
  • aronchick  · 技术社区  · 14 年前

    我们在Ruby中捕获了一些看起来很奇怪的代码,我想知道是否有人可以解释它:

    $ irb
    irb(main):001:0> APPLE = 'aaa'
    => "aaa"
    irb(main):002:0> banana = APPLE
    => "aaa"
    irb(main):003:0> banana << 'bbb'
    => "aaabbb"
    irb(main):004:0> banana
    => "aaabbb"
    irb(main):005:0> APPLE
    => "aaabbb"
    

    明白了吗?常量同时附加到了局部变量。

    已知行为?预期?

    4 回复  |  直到 13 年前
        1
  •  4
  •   Jörg W Mittag    14 年前

    明白了吗?常量同时附加到了局部变量。

    不,它没有附加到,也不是局部变量。

    这个 单一的 对象 二者都 所引用的常量和局部变量已附加到,但常量和局部变量均未更改。您不能在Ruby中修改或更改变量或常量(至少不能像您的问题所暗示的那样),这是您 可以 改变就是对象。

    只有两件事你 可以 处理变量或常量是取消引用并分配给它们。

    常数在这里是一个红鲱鱼,它与给出的例子完全无关。唯一相关的是 整个示例中的单个对象。可以使用两个不同的名称访问单个对象。如果对象更改,则对象更改。时期。它不会神秘地一分为二。使用哪个名称查看更改的对象并不重要。反正只有一个对象。

    这与任何其他编程语言完全一样:如果你有多个引用,比如Python、Java、C、C++、C、LISP、SimulalTalk、JavaScript、PHP、Perl等,那么无论使用什么引用,对该对象的任何更改都是可见的,即使这些引用中的一些引用也是可见的。 final const 或是任何一种特定的语言。

    这就是共享可变状态的工作原理,也是共享可变状态不好的原因之一。

    在Ruby中,通常可以调用 freeze 方法,使其不可变。但是,您再次修改了 对象 在这里,任何其他引用该对象的人都会突然发现该对象已变得不可变。因此,为了安全起见,您需要首先通过调用 dup . 当然,如果你想到一个数组,这也不够,例如:如果你 DUP 阵列,你会得到不同的 数组 但是对象 里面 数组仍然是原始数组中的相同数组。如果你 冻结 数组,则不能再修改 数组 但是对象 在里面 数组很可能仍然是可变的:

    ORIG = ['Hello']
    CLONE = ORIG.dup.freeze
    CLONE[0] << ', World!'
    CLONE # => ['Hello, World!']
    

    这是你的可变状态。摆脱这种疯狂的唯一方法要么是放弃共享状态(例如演员编程:如果没有其他人能看到它,那么不管它多久或何时改变)要么是可变状态(即功能编程:如果它从不改变,那么其他人看到它的多少也不重要)。

    原来例子中的两个变量之一实际上是一个常数,这与问题完全无关。Ruby中的变量和常量有两个主要区别:它们具有不同的查找规则,如果将常量分配给多个对象,它们将生成警告。但是在这个例子中,查找规则是不相关的,常量只分配一次,所以在这种情况下,变量和常量之间实际上没有区别。

        2
  •  5
  •   Community Paul Sweatte    7 年前

    已知行为。常量并不意味着你不能修改它所引用的对象,仅仅意味着如果你将它分配给一个不同的对象,它会给你一个警告(并且只有一个警告)。

    简而言之,Ruby常量不是。

    注释 :此行为列在 answer “应该警告新手什么是Ruby Gotchas?”这是一本值得一读的书。

        3
  •  0
  •   zaius    14 年前

    如果希望常量不可变,可以冻结它们:

    >> APPLE = 'aaa'
    => "aaa"
    >> banana = APPLE
    => "aaa"
    >> APPLE.freeze
    => "aaa"
    >> banana.frozen?
    => true
    >> banana << 'bbb'
    TypeError: can't modify frozen string
        from (irb):5:in `<<'
        from (irb):5
    
        4
  •  0
  •   Justin L.    14 年前

    Ruby中的常量不是“常量”。您也可以使用任何其他名称;如果不尝试更改指针的地址,则将它们全部大写不会改变对象的任何内容(以解释程序为准)。

    如果你这样看的话,行为是显而易见的,也是必要的;苹果是一个指向字符串对象的指针,香蕉也是。然后编辑香蕉指向的对象。苹果正指向同一个对象,所以变化也反映在那里。