【问题标题】:Method that returns the yield for an object in Ruby在 Ruby 中返回对象的产量的方法
【发布时间】:2011-11-26 18:55:40
【问题描述】:

Ruby 中有没有方法可以返回传递给对象的块的内容?

例如,如果我有一个想要放入数组的对象怎么办?

在理想的世界中,我们会做(我正在寻找的):

"string".reverse.upcase.something{ |s| send(s) }

这将返回一个包含我的对象的数组,相当于:

send("string".reverse.upcase)

如果我有我的对象开始并且在更复杂的场景中可能会变得混乱,则它是不可链接的。

因此something 方法将返回块的评估,如Array#map,但仅针对一个元素。

【问题讨论】:

  • returns the content of the block passed on to an object 是什么意思?
  • 该方法将评估块的内容并返回它。
  • “保持可链接性”是什么意思? JSON.parse(j) 的结果是什么?
  • @mlie 如果您查看第一个代码块,我们可以重用该方法的结果以将其传递给另一个方法,依此类推,“可链接性”。如果您查看第二个代码块,代码会更加混乱,因为该方法位于开头。 (我很难用语言表达,请随时编辑/评论)
  • 好的,现在我明白了。我个人认为是相反的:第二行的调用对我来说更清楚,花括号很难阅读,其他人必须知道something是什么意思......

标签: ruby object block yield chainability


【解决方案1】:

我不知道有这样的内置功能,但您可以自己轻松完成:

class Object
  def something(&block)
    block.call(self)
  end
end

p "foo".something { | o | [o] }
p 23.something { | x | p x; 42 }

给予

["foo"]      # object "foo" put into an array
23           # object handed to block
42           # something return block's result

【讨论】:

  • 未来的读者,这是在 Ruby 核心 2.5.0 中以Object#yield_self 实现的。请参阅我的更新答案。
【解决方案2】:

您在寻找Object.tap 吗?

【讨论】:

  • 不,Object#tap 返回调用该方法的对象,而我的方法将返回块的评估。
  • 有趣的技术,不知道。
【解决方案3】:

我有时希望标准库中也有类似的功能。例如,名称可以是 withwith_it

(以新名称重复之前的代码)

class Object
  def with_it(&block)
    block.call(self)
  end
end

示例用法:

x = [1, 2, 3, 4, 5].map {|x| x * x }.with_it do |list|
   head = list.unshift
   list << head * 10
   list.join " / "
end

相对于:

list = [1, 2, 3, 4, 5].map {|x| x * x }
head = list.unshift
list << head * 10
x = list.join " / "

虽然后者更容易理解,但前者的好处是保持变量 listhead 的作用域,并且在我看来对 x 的赋值更清楚(对 x 的赋值必须插入到代码的最后一行)。如果代码是更大方法的一部分,范围界定将是一个好处。

因此,使用with_it 的另一种选择是将代码放在单独的方法中。例如:

def mult_head_and_join(list)
    head = list.unshift
    list << head * 10
    list.join " / "
end

x = mult_head_and_join [1, 2, 3, 4, 5].map {|x| x * x }

不知道在这里结束什么,但我想我会投票支持将 with_it 包含在标准库中

【讨论】:

    【解决方案4】:

    在最初的问题六年后,Ruby 2.5.0 引入了 Object#yield_self,然后在 Ruby 2.6 中缩短为 #then

     class Object
       def yield_self(*args)
         yield(self, *args)
       end
     end
    

    [...]

    它执行块并返回它的输出。

    (Ruby Feature #6721)

    例如:

    2.then{ |x| x*x }  # => 4
    

    【讨论】:

      猜你喜欢
      • 2011-11-03
      • 2020-11-18
      • 2015-12-20
      • 2018-05-28
      • 2018-02-25
      • 1970-01-01
      • 2012-03-01
      • 2014-09-26
      • 1970-01-01
      相关资源
      最近更新 更多