在Ruby中修改匿名数组中的模块级变量

时间:2009-09-29 06:06:10

标签: ruby map

我正在学习Ruby,并认为我对以下代码很聪明:

[@start,@end].map!{ |time| time += operation == :add ? amount : -(amount) }

其中@start,@ end是两个模块级变量,操作可以是以下之一:add或:sub,而amount是一个浮点数,用于调整@start和@end by。

当然,它只为我节省了一行代码,但为什么这种方法不起作用,我怎么能得到类似的呢?

(我的预期输出是相应地修改@ start / @ end,但是单元测试显示它们保持原始值。)

3 个答案:

答案 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)

块中的加法操作不会修改“时间”,它会返回一个新值。因此,数组中的元素不会被修改,而是被替换。