Ruby 像tap这样的组合方法,但能返回不同的值吗?
我正在经历一个尝试避免临时变量和过度使用条件变量的阶段,我可以使用更流畅的编码风格。我非常喜欢在需要返回值的地方使用Ruby 像tap这样的组合方法,但能返回不同的值吗?,ruby,theory,combinators,Ruby,Theory,Combinators,我正在经历一个尝试避免临时变量和过度使用条件变量的阶段,我可以使用更流畅的编码风格。我非常喜欢在需要返回值的地方使用#tap,但在返回值之前先对其进行处理 def fluid_method something_complicated(a, b, c).tap do |obj| obj.update(:x => y) end end 对程序性: def non_fluid_method obj = something_complicated(a, b, c) obj
#tap
,但在返回值之前先对其进行处理
def fluid_method
something_complicated(a, b, c).tap do |obj|
obj.update(:x => y)
end
end
对程序性:
def non_fluid_method
obj = something_complicated(a, b, c)
obj.update(:x => y)
obj # <= I don't like this, if it's avoidable
end
obj = whatever
things.each do |thing|
obj = thing.filter(obj)
end
obj
对程序性:
def non_fluid_method
obj = something_complicated(a, b, c)
obj.update(:x => y)
obj # <= I don't like this, if it's avoidable
end
obj = whatever
things.each do |thing|
obj = thing.filter(obj)
end
obj
现在,我面临着重复使用类似以下情况的情况,并寻求一种更流畅的方法来处理它:
def not_nice_method
obj = something_complex(a, b, c)
if a_predicate_check?
obj.one_more_method_call
else
obj
end
end
(稍微)干净的解决方案是以重复为代价避免临时变量:
def not_nice_method
if a_predicate_check?
something_complex(a, b, c).one_more_method_call
else
something_complex(a, b, c)
end
end
不过,我还是忍不住想在这里使用类似于#tap
的东西
我还可以遵循什么样的模式呢。我意识到这对一些人来说都是无稽之谈,我应该转向更有趣的问题,但我正在努力学习以更实用的风格写作,所以我只是好奇,长期红宝石爱好者决定用什么好方法来处理这种情况。这些示例被大大简化。将对象定义为:
class Object
def as
yield self
end
end
现在你可以写:
def not_sure_this_is_nice_enough_method1
something_complex(a, b, c).as do |obj|
a_predicate_check? ? obj.one_more_method_call : obj
end
end
我在Facets gem中找到了一种可能正是您所寻找的方法:
所以你最初的方法是:
def not_nice_method
obj = something_complex(a, b, c)
if a_predicate_check?
obj.one_more_method_call
else
obj
end
end
可能最终看起来像这样:
require 'facets/kernel/ergo'
def nice_method
something_complex(a, b, c).ergo do |_|
a_predicate_check? ? _.one_more_method_call : _
end
end
我需要这样做,我喜欢tokland的答案,但我不想因为我正在写的小脚本而污染Object。相反,我在数组上使用了tap
:
[something_complicated].tap { |s| s[0] = new_cool_thing)}.first
神奇的是点击中的中断
返回另一个值
新的
ruby 2.5提供了您想要的yield\u self
。
实例评估
可能会被误用于此目的
“this”.instance_eval{| test | test+“works”}
从2.5开始,可以使用yield\u self
“简单”。产生自我{a{a+“豌豆”}
阅读更多:
尽管有学究的危险,但使用tap诱发副作用似乎是反功能的。函数式程序员和语言可以避免或防止副作用。tap的要点是它不会返回在其中执行的内容。因此,可以使用两种方法:调试和引起副作用的方法。函数式方法只是将方法链接在一起或组合它们。没有风险,我想谈谈理论,尽管我担心如果没有直接的问题,这个线程会被关闭,但是,考虑到#update
将返回布尔值,而不是obj
的值(这是我无法控制的),tap不解决第三个表达式返回原始值的需要吗?我想了解更多正确的函数技术:)啊,我知道如何改变它:update(复杂的东西(a,b,c))
,在这里我定义了update
来做参数。update(:x=>y)
。。。虽然这会因为更新参数需要传入而变得更加详细,但这只是编写lambda并调用它的语法糖分。你可以让它改变一个链中间的值,比如<代码> 3.TWISW { i i* i * 2 },返回6 ,这相当于<代码> lambda { 3×2 }。它还可以让你创建和使用中间链的引用:5.tweak{id}obj=lookup(id);obj.ready?&&obj.valid?}
这相当于lambda{obj=lookup(id);obj.ready?&&obj.valid}。call
哦,你的对象#as
技巧(在我看来)肯定比赋值更好;if..else..end
版本。你可能会有一个some_方法(a,b).on(a_谓词?{| obj | obj.whatever}
。我可以把你的当作
,稍微颠倒一下,给调用者添加with
:with(something_complex(a,b)){| obj | a|u predicate?obj.whatever:obj}
。Hmmm.@d11wtq:on{}看起来也不错,通常最好调用一个方法,而不是用send(:methods)包装隐藏它(问题是你必须给它命名)。请注意,您的with(x){| x |…}实际上是Ick's let:Ick看起来很有趣,尽管我怀疑它不会很好地与RSpec配合,因为它有一个自己的let
方法,其行为完全不同:)对象#as
方法应该完全在源代码中。在许多情况下,它变得有用!(我在那里问过:)Ruby 2.5获得了yield\u self
方法,基本上就是这里实现的as
。@kuboon的回答中也提到了这一点。更容易[bla]。收集{bla |“bla”}。首先
Ruby 2.6添加别名,然后
到#yield#u self
。