ruby中内核#yield_self,yield(self)和Object#tap之间的区别
Ruby 2.5.0-rc1已经发布并引入了一个新的Kernel#yield_self
方法。
yield_self
, yield(self)
和现有的Object#tap
方法有什么区别?
tap
和yield_self
之间的区别在于两种方法中的每一种返回的内容。
Object#tap
为块生成self ,然后返回self 。 Kernel#yield_self
为块生成self,然后返回块的结果 。
以下是一些有用的示例:
龙头
替换方法结尾处对result
行的需求:
def my_method result = get_some_result call_some_method_with result result end
可以写成:
def my_method get_some_result.tap do |result| call_some_method_with result end end
另一个例子是初始化一些对象,需要几个步骤:
some_object = SomeClass.new.tap do |obj| obj.field1 = some_value obj.field2 = other_value end
yield_self和yield(self)
如果在你自己的一个方法中使用, yield_self
将与yield(self)
具有相同的效果。 但是,通过将其作为一种方法,这促进了方法链接作为嵌套函数调用的替代方法。
MichałŁomnicki撰写的这篇博文有一些有用的例子。 例如这段代码:
CSV.parse(File.read(File.expand_path("data.csv"), __dir__)) .map { |row| row[1].to_i } .sum
可以改写为:
"data.csv" .yield_self { |name| File.expand_path(name, __dir__) } .yield_self { |path| File.read(path) } .yield_self { |body| CSV.parse(body) } .map { |row| row[1].to_i } .sum
这有助于清楚地将嵌套调用用于某些数据的一系列转换。 其他编程语言中也存在类似的特征。 Elixir的管道操作员是个好看的人,
这里有一个很好的总结: Ruby 2.5添加了yield_self 。
快速更新: yield_self
将在新版本的Ruby中有一个别名,遵循社区的请求,使其更具可读性。
这是一篇非常好的,简洁的阅读,下面引用后代。 归功于原作者Vijay Kumar Agrawal:
Ruby 2.5添加了一个名为yield_self的新方法。 它产生给定块的接收器并返回块中最后一个语句的输出。
irb> "Hello".yield_self { |str| str + " World" } => "Hello World"
它与Rails中的尝试有什么不同?
没有方法参数,try的行为类似于yield_self。 它将屈服于给定的块,除非接收器为nil并返回块中最后一个语句的输出。
irb> "Hello".try { |str| str + " World" } => "Hello World"
需要注意的几点差异,尝试不是Ruby的一部分,而是Rails。 另外尝试的主要目的是防止nil因此如果接收器为零则不执行块。
irb> nil.yield_self { |obj| "Hello World" } => "Hello World" irb> nil.try { |obj| "Hello World" } => nil
点击怎么样?
tap也类似于yield_self。 它是Ruby本身的一部分。 唯一的区别是返回的值。 tap返回接收器本身,而yield_self返回块的输出。
irb> "Hello".yield_self { |str| str + " World" } => "Hello World" irb> "Hello".tap { |str| str + " World" } => "Hello"
总的来说,yield_self通过促进对嵌套函数调用的链接来提高代码的可读性。 这是两种风格的例子。
irb> add_greeting = -> (str) { "HELLO " + str } irb> to_upper = -> (str) { str.upcase } # with new `yield_self` irb> "world".yield_self(&to_upper) .yield_self(&add_greeting) => "HELLO WORLD" # nested function calls irb> add_greeting.call(to_upper.call("world")) => "HELLO WORLD"
yield_self是内核的一部分,因此它可用于所有对象。
请不要接受这个作为答案,因为这不是我自己的手工(我很乐意删除,如果有人有任何异议) – 但我发现这是一个非常好的阅读,并认为它可能在某些时候帮助其他人。
我想补充mikej关于each
与map
之间的并行性和tap
与yield_self
之间的并行性的答案。
有许多问题要求each
和map
之间的区别为可枚举。 前者用于做一些副作用或破坏性的东西,然后返回接收器,这对于链接方法很方便。 后者返回评估值以代替接收器中的每个元素。
tap
vs. yield_self
就是这样; 区别在于它们是针对单个接收器对象而不是可枚举接收器中的元素完成的。 所以他们的用例与我上面写的一致。 前者用于做一些副作用或破坏性的东西,然后返回接收器,这对于链接方法很方便。 后者返回评估值而不是接收者。
- sRails 4.2 / Rspec / rspec-retry – 关联属于/ has_many失败
- 如何在Rails 2.3.5中从模型中呈现部分
- 如何解决Marshal.dump“没有为类Proc定义marshal_dump”错误
- rvm install ruby-1.9.3-p286:运行’make -j 9’时出错(OSX:Mountain Lion)
- 模型中未定义的方法`truncate’
- 在iso8601中输出Ruby持续时间
- 无法在Windows上运行捆绑软件更新
- 在http标头中设置身份validation令牌
- 您的软件包已锁定到rake(12.0.0),但在Gemfile中列出的任何源中都找不到该版本。