红宝石“做”迭代循环的结果是什么?

时间:2018-08-29 20:38:08

标签: ruby

我有以下的ruby方法:没有任何dobreaknext的单个return迭代。 cats是cat对象的数组;如果cat的颜色为红色,则is_cat_red的值为true

def get_non_red_cats cats
  cats.each do |cat|
    !is_cat_red?(cat)
  end
end

方法返回什么(循环求值)?

2 个答案:

答案 0 :(得分:1)

这是一些不寻常的代码,它完全取决于cats方法的作用。您可以将一个块传递给任何Ruby方法,并且该方法可以在立即与程序执行结束之间的任意时间执行零次

返回值是cats返回的值,此代码段尚不清楚。

用JavaScript术语来想象一下,因为这种语言的含糊性大大降低了:

function get_non_red_cats(cats) {
  return cats(function(cat) {
    return !is_cat_red?(cat);
  }
}

这表明cats只是一个可能具有功能的功能。它也可能会忽略您的功能。

现在,如果cats.each会改变事物,因为Enumerable each method可能具有明确的行为。

在这种情况下,返回值就是cats

答案 1 :(得分:1)

您的代码中没有循环。 Ruby有两种循环:whilefor / in。 (实际上,后者只是each的语法糖。)

在Ruby中,一个表达式的值等于该表达式内部最后一个子表达式的值。消息发送的结果是作为消息发送结果执行的方法的返回值。方法的返回值明确地是结束方法执行的return表达式的值,或者隐式地是在方法主体内求值的最后一个表达式的值。 (请注意,在主体内部求值的最后一个表达式也是模块或类定义表达式求值的内容。但是,方法定义表达式的求值结果是表示方法名称的Symbol。)

那么get_non_red_cats返回什么?好吧,其中没有return,因此它返回在方法主体中求值的最后一个表达式的值。在方法主体内部求值的最后一个表达式是将消息each发送到参数绑定cats所引用的对象的消息。因此,get_non_red_cats的返回值是由于向each发送cats消息而执行的方法的返回值。

这就是我们肯定知道的全部内容。

不过,我们可以做一些假设。通常,each 应该返回self。这就是整个核心库和标准库中each的所有实现,它是Ruby中标准“ 可迭代”协议的一部分。如果不是这种情况,那将是非常不寻常且令人困惑的。因此,我们可以假设,无论each的任何实现最终被执行,它将返回self,即消息发送的接收者,即参数所引用的对象绑定cats

换句话说:方法get_non_red_cats仅返回作为参数传递的任何内容。这是一种很无聊的方法。实际上,这是 identity方法,几乎是最无聊的方法。

但是,它可能有副作用。您并没有询问副作用,而只是询问返回值,而是让我们看看它。

由于each应该只是返回其接收者,因此在某种意义上,它也是 identity方法,因此非常无聊。 但是each通常应该评估它所传递的块,并依次将集合的每个元素作为参数传递。但是,它忽略了该块求值的值;仅对块的副作用进行评估。请注意,each的块没有副作用。如果该块没有副作用,那么关于该块的唯一有趣的事情就是它的值,但是each 忽略该块的值,并简单地返回self

foo.each do
  # something that has no side-effect
end

完全等同于

foo

另一种Ruby约定是,消息以问号?结尾发送,应该用于提问(不是!),即以问号结尾的消息发送应返回适合用作条件的内容。通常,它也不应有副作用。 (这称为命令查询分离原理,是面向对象软件构造的基本设计原理。)

最后,!一元前缀运算符在应用于要在条件中使用的对象(即布尔值或等效值)时,通常不具有副作用。因此,由于在块中发送的消息以问号结尾,因此不应该具有副作用,并且!运算符也不应当具有副作用,我们可以假定整个方块都没有副作用。

这反过来意味着each不应该有副作用,因此get_non_red_cats不应该有副作用。结果,get_non_red_cats唯一要做的 other 操作就是返回一个值,并且很可能只是返回传入的值。

Ergo,整个方法等效于

def get_non_red_cats(cats)
  cats
end

所有这些都是假设,作者遵循了标准的Ruby约定。如果她不这样做,则此方法可以执行任何操作并返回任何,它可以格式化硬盘,发动核攻击,返回42或完全不执行任何操作。