2009-09-29 57 views
2

匿名阵列模块级变量我在学习Ruby之中,以为我很聪明用下面的代码:修改在Ruby中

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

其中@启动,@end两个模块级变量,操作可以是以下之一:add或:sub,并且amount是一个float值,用于调整@start和@end by。

授予它只会节省我一行代码,但为什么这种方法不工作,我怎么能得到类似的东西呢?

(我的预期输出为@开始/结束@相应地修改,但是单元的测试表明,它们留在它们的原始值。)

回答

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业务faffing周围要么 - 我们就可以通过邮件的实际名称,我们要发送(在这种情况下,我使用+,但它可以是任何东西)。

如果你有一个大的,动态生成的ivars列表,你想设置,这只是一点点复杂。唯一的区别是需要按名称获取和设置ivars。

ivars = [:@start, :@end, :@something_else] 
operation = :+ 
amount = 12 
ivars.each {|ivar| instance_variable_set(ivar, instance_variable_get(ivar).send(operation, amount))} 
+0

非常感谢。假设不适用于Ruby。 – cfeduke 2009-09-29 14:09:50

2

在块中的加法操作不修改“时间” ,它会返回一个新值。所以数组中的元素不会被修改,它们会被替换。

+0

这是有道理的。我想没有办法让我的代码工作,因为我想写它。 – cfeduke 2009-09-29 06:29:06

3

+=运营商改变了time的价值,但它返回的time旧值,因此正确的代码是:

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

编辑 更新代码真正改变@start@end

+0

嗯,仍然没有骰子。 @start + =操作==:添加?金额: - (金额)正在工作,但不是当我尝试通过Array#map block来完成时。 :( – cfeduke 2009-09-29 06:55:12

+0

是的,这是有效的,谢谢!(我正在挑选Chuck的答案,因为他很好地解释了引擎盖下发生了什么,以及我如何能够对Ruby思考) – cfeduke 2009-09-29 14:09:05