【发布时间】:2022-01-02 18:10:26
【问题描述】:
在 Elixir 中有一个很棒的管道操作员是这样工作的:
"hello, world!"
|> String.split(" ")
|> Enum.map(&String.capitalize/1)
|> Enum.join
在 Ruby 中我们可以使用类似的语法:
"hello, world!"
.split(" ")
.map(&:capitalize)
.join
只有在为对象本身定义了所有这些方法时才有效。如果需要调用一些本地方法,我们应该使用类似:
.map { |el| URI.parse(el) }
但是如果我们想做一些集合处理(不是单个元素),例如 GZIP 压缩:
chars = text
.downcase
.chars
compressed = GZipped.new(chars).bytes
但是链条断了!
我找到了一些链接,但看起来不太好:
- pipe_envy - 丑陋!没有收藏
- chainable_methods - 没有收藏
- How to use chainable_methods
- piperator - 好多了!但看起来很重
在我看来,有这样的东西会很棒:
text
.split
.pipe(URI.method(:parse))
.map(&:to_s)
.join
.pipe(GZIPped)
.pipe(Base64.method(:encode))
在 Ruby 中构建此类管道的最佳方法是什么?
更新 1
这是一个例子
class Dedup
def initialize(obj)
@obj = obj
end
def each
Enumerator.new do |y|
prev = nil
@obj.each do |el|
if el != prev
y << el
prev = el
end
end
end
end
end
expect(
"1 1 1 2 2 3"
.split
.then { |obj| Dedup.new(obj).each }
.to_a
).to eq [1, 2, 3]
这种链接看起来丑陋且难以阅读。
比较:
expect(
"1 1 1 2 2 3"
.split
.pipe(Dedup)
.to_a
).to eq [1, 2, 3]
【问题讨论】:
-
根据我的经验,试图让一种语言模仿另一种语言很少奏效。我宁愿以惯用代码为目标,使用 Ruby 提供的语言工具。
-
@Stefan 你能提供一些
idiomatic的 Ruby 风格的代码吗? -
在elixir 中也不鼓励为了管道而进行管道。声明一个局部变量
chars并在其上调用GZipped.new(chars)。除非你在愚弄队友之后,否则长管道没有什么好处。 -
@SergeiO.Udalov 示例代码似乎很做作。你有一个实际的问题想要解决吗?
-
是的。真实案例是将elixir代码移植到ruby。是的,我们可以用 ruby 方式重写它,但最好保持尽可能接近。
标签: arrays ruby functional-programming pipe elixir