我经常发现自己编写的ruby代码如下:
b = f1(a)
c = f2(b)
d = f3(c)
...
有没有办法将f1
,f2
,f3
链接在一起,无论a,b和c的类型如何?例如
a.send_to(&:f1)
.sent_to(&:f2)
.sent_to(&:f3)
它不一定是那个,但我喜欢可以按顺序阅读的代码,“从a
开始,现在应用f1
,然后应用{{1} },...“
在我看来,我真正要求的是在单个对象而不是列表上使用f2
的方法。例如。我能做到这一点:
map
以下(有点)工作,虽然猴子修补[a].map(&:f1)
.map(&:f2)
.map(&:f3)
.first
似乎是一个坏主意:
Object
我说“(有点)有效”因为
class Object
def send_to(&block)
block.call(self)
end
end
但
1.send_to{|x| x+1}
#=> 2
注意:This question提出类似的问题,但建议是在每个对象的特定类上定义一个方法。
答案 0 :(得分:5)
你可以这样做:
d = [:f1, :f2, :f3].inject(a) { |res,f| send(f, res) }
答案 1 :(得分:4)
我认为你想要的基本上是注入和发送的组合。类似的东西:
d = [:f1, :f2, :f3].inject(a) {|memo, fun| send(fun, memo) }
答案 2 :(得分:3)
如果您觉得有必要经常这样做,那么您的API设计作为Ruby代码是错误的。而不是在函数风格中定义方法:
b = f1(a)
c = f2(b)
d = f3(c)
...
以OOP样式定义它们:
class A
def f1; ... end # => b instance
end
class B
def f2; ... end # => c instance
end
class C
def f3; ... end # => d instance
end
此处,A
是a
所属的类,B
是b
所属的类,依此类推(A
,{ {1}},...不必完全不同。如果您想允许任何对象,它们可以是B
或Object
。然后,您可以简单地进行链接:
Kernel
答案 3 :(得分:1)
Ruby 2.5的.yield_self
正是这样做的!
https://zverok.github.io/blog/2018-01-24-yield_self.html
如果我正确地遵循了这一讨论,那么.then
现在就是.yield_self
的别名
https://www.reddit.com/r/ruby/comments/8nfqmt/kernelthen_is_now_an_alias_for_kernelyield_self/
答案 4 :(得分:0)
如果您从f3
功能开始,则无需更改任何内容
其次,省略括号的能力很强。
例如:
a = 42
def f1 n; n end
def f2 n; n end
def f3 n; n end
f3 f2 f1 a
# => 42
使用更复杂的功能,您可以添加括号。