【问题标题】:What's the rationale for the block argument?块参数的基本原理是什么?
【发布时间】:2017-02-04 22:41:47
【问题描述】:

我刚刚学习 Ruby,并且无法理解所谓的“块参数”(可以附加到方法调用)的意义。

AFAICT,“块参数”的工作方式与其他编程语言(或 Ruby 本身)中的任何普通回调参数一样,但在最多只能附加一个“块参数”到方法调用,而方法/函数可以设计接受的回调参数的数量没有上限。

(如果需要澄清,我所说的“回调”是指一个函数 F 另一个函数 G 接收(作为其参数之一)并依次接收电话。)

我认为必须有 一些事情可以用块参数来做,而 就像用回调一样容易(否则,很难证明支持块参数的特殊语法),但我无法弄清楚这个“东西”可能是什么。

我的问题是:

使用常规回调无法完成的“块参数”可以做什么?


编辑:较早的评论(现已删除)说块参数更好地描述为“闭包”而不是“回调”。在我的书中,闭包是回调的一个特例。如果愿意,可以在我的帖子中将“回调”替换为“关闭”。帖子的问题仍然存在(当然,除非“块参数”是在 Ruby 中创建闭包的唯一方法,但如果是这种情况,它本身会提出比它回答的问题更多的问题)。

【问题讨论】:

标签: ruby


【解决方案1】:

我认为必须有一些事情可以用块参数做,而不能像回调一样容易做到(否则,

是的。块是一种“语法糖”,但它们在功能上也与 JavaScript 等语言中的“回调函数”大不相同。

一方面,return 关键字的作用与它在 Ruby 和其他语言中的函数和方法中的作用非常不同。

在块内,return 跳出 包含方法,而在方法中 return 跳出(显然)方法。

这对于以下情况很重要:

def find_by_email(users, search_email)
  users.each do |user|
    # return all the way out of find_by_email
    return user if user.email == search_email
  end

  nil
end

在这里,我们使用each 来迭代一个集合。如果某个条件是我在块内,则返回用户一直退出包含方法

这不适用于函数。比较“相同”的 JavaScript 代码,它不能按预期工作:

function findUserByEmail(users, searchEmail) {
  users.forEach(function (user) {
    if (user.email == searchEmail) {
      // return out of `forEach`
      return user;
    }
  });
  // broken
}

【讨论】:

  • 好吧,我想我明白了:block 参数几乎就像是直接“注入”(或“移植”)到方法中的一段代码......这样的参数有限仍然令人费解最多一个。如果允许多个,则相当于一种内置语法来支持策略/策略模式。
【解决方案2】:

我认为使用传递函数(例如在 javascript 中)无法完成的块无法完成任何事情。 我认为 ruby​​ 的创建者认为在 95% 的情况下,您只想将一个回调传递给函数,而不是更多。所以他们为此创建了非常好的语法:

 Post.all.map { |post| puts post.title } 

与javascript比较

$(document).on('click', function() {
   DO SOMETHING
 }

总而言之:我认为传递块是 ruby​​ 中的语法糖,与 js 中的传递函数相当,但更好看。在大多数情况下,无论如何您都希望传递一个块(或回调)。

【讨论】:

  • 为了记录,现代 JS 大大简化了syntax for anonymous functions没有,从而限制了这些函数中有多少可以作为参数传递给其他函数。