我经常使用|| =运算符来减少冗余调用。我想采取这样的东西
@my_variable ||= my_calculation_method
并将其转换为
@my_variable.assign { code_block }
使用这个想法
class Object
def assign
if self.instance_of? NilClass
self = yield
end
end
end
正如您可能已经猜到的那样,分配self
没有意义且不起作用。
如何访问@my_variable
方法中的assign
指针来修改值?
答案 0 :(得分:5)
如果你的初始化逻辑是非常重要的并跨越几行(我认为这是问题的前提),那么你可以做什么,用惯用的ruby:
@my_variable ||= begin
# code block
end
我通常做的是将逻辑拆分为两部分。记忆与计算分开。你的第一行就是这个。
def stats
@stats ||= compute_stats
end
def compute_stats
...
end
我发现XXX + compute_XXX的这种模式很容易识别/跟随。
答案 1 :(得分:3)
self = x
完全不可能。你无法告诉对象它是什么,永远不会改变。如果它是用特定的类创建的,那么它会与同一个类一起死掉。您所能做的就是修改该对象或其关联的类,但该对象的类是不可变的。
@x ||= y
工作的唯一原因是因为@x
只是一个变量,它是一个指向对象的指针,这是你可以重新分配的东西。说@x = z
不会改变对象,它只会改变指针。 self
是一种特殊情况,它指的是您在其中运行的上下文,并且无法重新分配。
请注意,如果您的self = yield
来电成功,您将重新定义nil
程序范围的内容。
这整个努力都是错误的,||=
模式在这一点上几乎是惯用的Ruby。如果你想改进那种模式,那么你想做的就是制作一些alternative to memoize。
答案 2 :(得分:2)
正如塔德曼所说,你不能写self =
。但是你可以编写一个方法,它接受实例变量的名称并设置它。
你有评论说这是'不优雅'或'误入歧途'。虽然我不同意这种判断,但优良作法是编写尽可能使用标准约定的不起眼的代码。这有助于其他人轻松理解您的代码。即为||=
这样的基本ruby方法编写替代语法可能效率不高;其他人将不得不大量挖掘您的代码以了解事情的运作方式。
话虽如此,为了教会如何让Ruby做你想做的事,我可以为此建议这个Object
方法:
class Object
def assign(key)
# make sure the key is a valid instance variable
unless key =~ /^[A-Za-z0-9\_]+$/
raise ArgumentError, "#{key} is not a valid ivar name"
end
if instance_variable_get("@#{key}").nil?
instance_variable_set("@#{key}", yield)
end
end
end
# example
class Foo
def set_bsd
assign("bsd", yield)
end
end
foo = Foo.new
foo.assign("my_ivar") { "val" }
foo
# => #<Foo:0x007fc2e4ccaca0 @asd=1>
foo.set_bsd { 2 }
foo
# => #<Foo:0x007fc2e4ccaca0 @asd=1 @bsd = 2>
虽然我建议不要以这种方式修补Object
- 它太普通了,并且可能与内部功能发生意外冲突。而是将此功能添加到自定义类/模块,并include
模块或继承该类。