На что рассчитывает итерационный цикл ruby ​​'do'? - PullRequest
0 голосов
/ 29 августа 2018

У меня есть следующий метод ruby: одна do итерация без break, next или return. Здесь cats - массив объектов cat; is_cat_red оценивается как true, если кошка имеет свойство цвета красного цвета.

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

Что возвращает метод (что вычисляет цикл)?

Ответы [ 2 ]

0 голосов
/ 30 августа 2018

В вашем коде нет цикла. В Ruby есть два вида циклов: while и for / in. (На самом деле, последний является просто синтаксическим сахаром для each.)

В Ruby выражение оценивается как значение последнего подвыражения, вычисленного внутри выражения. Отправка сообщения оценивается как возвращаемое значение метода, который был выполнен в результате отправки сообщения. Возвращаемое значение метода - это либо явно значение выражения return, которое завершило выполнение метода, либо неявно значение последнего выражения, вычисленного внутри тела метода. (Обратите внимание, что последнее выражение, вычисленное внутри тела, также является тем, что оценивает выражение определения модуля или класса. Однако выражение определения метода оценивается как Symbol, обозначающее имя метода.)

Итак, что возвращает get_non_red_cats? Ну, в нем нет return, поэтому он возвращает значение последнего выражения, вычисленного внутри тела метода. Последнее выражение, вычисленное внутри тела метода, представляет собой отправку сообщения each объекту, на который ссылается параметр привязки cats. Следовательно, возвращаемое значение get_non_red_cats - это возвращаемое значение метода, который выполняется в результате отправки сообщения each на cats.

И это все, что мы положительно знаем .

Мы можем сделать некоторые предположения , хотя. Как правило, each должно возвращать self. Это то, что делают все реализации each во всей базовой и стандартной библиотеках, и это часть стандартного протокола Iterable в Ruby. Было бы очень необычно и очень запутанно, если бы это было не так. Таким образом, мы можем предположить , что независимо от того, что реализация each завершится выполнением, она вернет self, то есть получателя отправленного сообщения, т.е. объект, на который ссылается параметр привязки cats.

Другими словами: метод get_non_red_cats просто возвращает то, что было передано в качестве аргумента. Это довольно скучный метод. На самом деле, это метод идентификации , который в значительной степени самый скучный из возможных.

Однако, может иметь побочный эффект. Вы не спрашивали о побочных эффектах, только о возвращаемом значении, но давайте все равно посмотрим на это.

Поскольку each должен просто возвращать свой получатель, в некотором смысле это также метод идентификации и, таким образом, чрезвычайно скучный. Однако , 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 может сделать, это вернуть значение, и очень вероятно, что оно просто возвращает значение, которое было передано.

Ergo, весь метод эквивалентен

def get_non_red_cats(cats)
  cats
end

Все это при условии , что автор следовал стандартным соглашениям Ruby. Если бы она этого не сделала, то этот метод мог бы сделать и вернуть что угодно вообще, он мог бы отформатировать ваш жесткий диск, запустить ядерную атаку, вернуть 42 или вообще ничего не делать.

0 голосов
/ 29 августа 2018

Это необычный код, и он полностью зависит от того, что делает метод cats. Вы можете передать блок любому методу Ruby, и этот метод может быть выполнен ноль еще больше в любой точке между немедленно и окончанием выполнения программы .

Возвращаемое значение - это то, что возвращает cats, что не ясно из этого фрагмента.

Представьте себе это в терминах JavaScript, так как этот язык намного менее неоднозначен:

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

Где это показывает, что cats - это просто функция, которая потенциально принимает функцию. Это может игнорировать и вашу функцию.

Теперь, если это cats.each, это меняет ситуацию, поскольку это, вероятно, Enumerable each метод , который имеет четко определенное поведение.

В этом случае возвращаемое значение равно 1023 *.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...