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