我正在学习Ruby,并认为我对以下代码很聪明:
[@start,@end].map!{ |time| time += operation == :add ? amount : -(amount) }
其中@start,@ end是两个模块级变量,操作可以是以下之一:add或:sub,而amount是一个浮点数,用于调整@start和@end by。
当然,它只为我节省了一行代码,但为什么这种方法不起作用,我怎么能得到类似的呢?
(我的预期输出是相应地修改@ start / @ end,但是单元测试显示它们保持原始值。)
答案 0 :(得分:5)
在Ruby中记住变量与它们所拥有的对象之间的区别非常重要。简单地设置变量永远不会改变该变量引用的对象。执行a += b
时,它只是a = a + b
的简写。因此,您要为变量a分配一个新值,而不是更改曾经存在的对象或更改对该对象的任何其他引用。因此,更改变量time
不会更改@start
。
为了分配实例变量,您需要实际分配给该实例变量。这是一种做你想要的方法:
operation = :+
amount = 12
@start, @end = [@start, @end].map {|time| time.send(operation, amount)}
您会注意到我们也没有对:add
和:sub
业务感到不满 - 我们只能传递我们要发送的邮件的实际名称(我在此处使用了+)案例,但它可能是任何事情。)
如果您想要设置一个动态生成的大型ivars列表,那么它只会有点复杂。唯一的区别是需要按名称获取和设置ivars。
ivars = [:@start, :@end, :@something_else]
operation = :+
amount = 12
ivars.each {|ivar| instance_variable_set(ivar, instance_variable_get(ivar).send(operation, amount))}
答案 1 :(得分:3)
+=
运算符会更改time
的值,但会返回旧值time
,因此正确的代码为:
@start,@end = [@start,@end].map!{ |time| time + (operation == :add ? amount : -amount) }
修改强>
更新了代码以实际更改@start
和@end
。
答案 2 :(得分:2)
块中的加法操作不会修改“时间”,它会返回一个新值。因此,数组中的元素不会被修改,而是被替换。