irb(main):001:0> def some_method
irb(main):002:1> begin
irb(main):003:2* xyz = 5
irb(main):004:2> zyx = 6
irb(main):005:2> end
irb(main):006:1> puts xyz
irb(main):007:1> puts zyx
irb(main):008:1> end
=> :some_method
irb(main):009:0>
irb(main):010:0* some_method
5
6
=> nil
在这个简单的例子中,开始/结束'块'(实际上是一个表达式)创建了两个在开始/结束之外可访问的变量(即xyz和zyx)。当然它确实如此:开头/结尾是一个表达。
我想要做的是以某种方式转换开始/结束,以便我可以在开始/结束时分解代码并将其放在别处,但仍然可以在some_method中创建变量。我怀疑这样做需要缩小范围,但我无法弄清楚如何做到这一点。
我想我想做点什么:
def some_method
create_variables_here
puts xyz
puts zyx
end
define_method :create_variables_here do
xyz=5
zyx=6
end
问题:
答案 0 :(得分:0)
你不想那样。你要求的是一个副作用,它是一个除了返回值以及修改自己的对象和参数之外的功能。更糟糕的是,它直接影响到来电者。副作用是可维护代码的祸根。它们打破了封装,让你必须仔细研究每个函数调用并考虑它的副作用。
通过返回值并将其赋值给变量可以更好地解决这个问题。 Ruby even supports returning multiple values,因此您可以将其作为两个值返回,而不是两个值的数组。
def create_variables_here
xyz=5
zyx=6
return xyz, zyx
end
def some_method
xyz, zyx = create_variables_here
puts xyz
puts zyx
end
你没有看到这么多,因为返回值通常是相关的,如果它们相关,它们应该作为单个对象返回。如果它们没有关系,这可能是一个很好的迹象,表明函数正在做太多事情。
它可以完成您想要的所有操作,并且可以让调用者决定调用哪些变量。这一点很重要,因为A)对于调用者来说是一个较少的东西,B)避免与函数中的变量发生冲突,C)使这些变量的来源变得明显。
作为一个反例,让我们说你有这个。
def some_method
do_this
do_that
do_some_other_thing
puts xyz
puts zyx
end
... xyz
和zyx
来自哪里?!通常答案很简单:它们是未初始化的。但是,根据您提出的功能,读者现在必须仔细检查每个do_blah
函数调用是否存在可能设置xyz
和zyx
的副作用。
(你可能会说,“但任何使用副作用变量的函数都应该有一个像create_vars_for_blah
这样的名字。”是的,它们应该,但你不能指望它。最好没有首先是危险的特征,而不是相信每个人都会谨慎使用它。)
更糟糕的是,如果他们所有将xyz
和zyx
设置为不同的值会怎样?现在你发生了冲突。调用者必须找到这种冲突,并做一些令人费解的事情,如:
def some_method
do_this
this_xyz = xyz
this_zyx = zyx
do_that
that_xyz = xyz
that_zyx = zyx
do_some_other_thing
some_other_xyz = xyz
some_other_zyx = zyx
...
end
这个想法的另一个问题是打破局部变量。局部变量最重要的一个方面是,您可以一目了然地查看可能影响它的所有代码。例如。
def some_method
xyz = 10
zyx = 20
do_this
do_that
do_some_other_thing
puts xyz
puts zyx
end
在普通的Ruby中,我们知道将打印10和20的事实。有了这个提议的功能,谁知道它们会是什么?
您要求的是在函数末尾消失的全局变量。