Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.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 attr_reader允许使用<;修改字符串变量&书信电报;_Ruby_Instance Variables - Fatal编程技术网

Ruby attr_reader允许使用<;修改字符串变量&书信电报;

Ruby attr_reader允许使用<;修改字符串变量&书信电报;,ruby,instance-variables,Ruby,Instance Variables,遇到了一些奇怪的行为,想知道是否有人能证实我所看到的 假设您使用成员变量创建了一个类,并允许使用attr_reader读取该类 class TestClass attr_reader :val def initialize(value) @val = value end end 现在,当我执行以下操作时,它似乎修改了@val的值,尽管我只授予它读取权限 test = TestClass.new('hello') puts test.val test.val <<

遇到了一些奇怪的行为,想知道是否有人能证实我所看到的

假设您使用成员变量创建了一个类,并允许使用attr_reader读取该类

class TestClass
  attr_reader :val

  def initialize(value)
   @val = value
  end
end
现在,当我执行以下操作时,它似乎修改了@val的值,尽管我只授予它读取权限

test = TestClass.new('hello')
puts test.val
test.val << ' world'
puts test.val

这只是我在irb中进行的一些测试的结果,因此不确定是否总是这样

您并不是在真正编写val属性。您正在阅读它并在其上调用一个方法(“只是对您的示例进行了一点修改:

test = TestClass.new([])
现在您应该获得(用p替换put以获得内部视图):

这是一样的。你“读取”val,现在你可以用它做一些事情。在我的例子中,你向数组中添加了一些东西,在你的例子中,你向字符串中添加了一些东西

读访问读取对象(可以修改),写访问更改属性(替换属性)

也许你在寻找冻结:

class TestClass
  attr_reader :val

  def initialize(value)
   @val = value
   @val.freeze
  end
end

test = TestClass.new('hello')
puts test.val
test.val << ' world'
puts test.val
虽然这似乎出乎意料,但这是完全正确的。让我解释一下

类宏方法定义实例变量的“getter”和“setter”方法

如果没有“getter”方法,您就无法访问对象的实例变量,因为您不在该对象的上下文中

def variable=(value)
  @variable = value
end

由于实例变量指向一个具有一组方法本身的可变对象,如果您“获取”它并对其进行操作,则这些更改将发生。您不需要使用上述setter方法调用
变量。赋值与修改不同,变量与对象不同

test.val = "hello world"
将是赋值给
@val
实例变量的情况(该变量不起作用),而


test.val
attr\u reader
表示您无法设置值,即未定义任何方法
value=
。这当然并不意味着您无法在对象上调用方法。请小心操作。您会希望复制该值,这样您就不会冻结其他人传入的变量。@JayMitchellI扩展了我的回答以捕获此副作用。感谢您的提示。您也可以在
initialize
中复制并冻结值,而不是实现另一种方法。例如,
@val=value.dup.freeze
(如果您知道
value
是一个字符串,您可以使用
@val=-value
完成相同的操作)
__temp.rb:12:in `<main>': can't modify frozen string (RuntimeError)
hello
class TestClass
  attr_reader :val

  def initialize(value)
   @val = value.dup.freeze  #dup to avoid to freeze the variable "value"
  end
end

hello = 'hello'
test = TestClass.new(hello)
puts test.val

hello << ' world' #this is possible
puts test.val  #this value is unchanged


test.val << ' world' #this is not possible
puts test.val
def variable=(value)
  @variable = value
end
test.val = "hello world"
test.val << " world"