Заявление о возврате - Return statement

В компьютерное программирование, а заявление о возврате заставляет выполнение оставить текущий подпрограмма и возобновить в точке кода сразу после инструкции, которая вызвала подпрограмму, известную как ее обратный адрес. Обратный адрес сохраняется вызывающей программой, сегодня обычно на процесс стек вызовов или в регистр. Операторы возврата на многих языках позволяют функции указывать возвращаемое значение быть переданным обратно в код который вызвал функцию.

Обзор

В C ++, возвращаться exp; (куда exp является выражение ) это утверждение который сообщает функции, что необходимо вернуть выполнение программы вызывающей функции и сообщить значение exp. Если функция имеет возвращаемый тип пустота, оператор return может использоваться без значения, и в этом случае программа просто вырывается из текущей функции и возвращается к вызывающей.

В Паскаль нет заявления о возврате. (Однако в новых версиях Паскаля Выход(exp); можно использовать для немедленного возврата значения. Без параметров она просто прерывает процедуру.) Подпрограмма автоматически возвращается, когда выполнение достигает своего последнего исполняемого оператора. Значения могут быть возвращены путем присвоения идентификатору, имеющему то же имя, что и подпрограмма, функция в терминологии Паскаля. Таким образом, идентификатор функции используется для рекурсивных вызовов и в качестве держателя результата; это синтаксически похоже на явное выходной параметр. Такой же синтаксис используется в Фортран 66 и Фортран 77 хотя оператор возврата был добавлен в FORTRAN II. В некоторых других языках вместо идентификатора функции используется определяемая пользователем переменная результата.

Оберон (Оберон-07 ) имеет предложение возврата вместо оператора возврата. Предложение return помещается после последнего оператора тела процедуры. Это позволяет во время компиляции проверять правильность возврата и возвращаемого значения из процедуры.

Немного язык программирования, ориентированный на выражения, Такие как Лисп, Perl и Рубин, позволяют программисту опустить явный оператор возврата, указав вместо этого, что последнее вычисленное выражение является возвращаемым значением подпрограммы.

В других случаях возвращается значение Null, если нет явного оператора возврата: в Python, Значение Никто возвращается, когда оператор return опущен, а в JavaScript значение неопределенный возвращается.

В Windows PowerShell все оцененные выражения, которые не записываются (например, присваиваются переменной, В ролях к пустота или же водопроводный к $ null ) возвращаются из подпрограммы как элементы в массиве или как отдельный объект в случае, если только один объект не был захвачен.

В Perl возвращаемое значение или значения подпрограммы могут зависеть от контекста, в котором она была вызвана. Наиболее фундаментальное различие - это скаляр контекст, в котором вызывающий код ожидает одно значение, список контекст, в котором вызывающий код ожидает список значений и пустота контекст, в котором вызывающий код вообще не ожидает никакого возвращаемого значения. Подпрограмма может проверить контекст, используя хочу функция. Для возврата неопределенного значения в скалярном контексте и пустого списка в контексте списка используется специальный синтаксис возврата без аргументов. Скалярный контекст можно далее разделить на Булево, номер, нить, и различные ссылка типы контекстов. Кроме того, контекстно-зависимый объект может быть возвращено с использованием контекстной возвращаемой последовательности с ленивая оценка скалярных значений.

Много операционные системы позволить программе вернуть результат (отдельный от обычного выход ) когда его процесс завершается; эти значения называются коды возврата, или более конкретно статусы выхода. Объем информации, который может быть передан таким образом, весьма ограничен, на практике часто ограничивается сигналом успеха или неудачи. Изнутри программы этот возврат обычно достигается вызовом Выход (системный вызов) (распространено даже в C, где альтернативный механизм возврата из основная функция доступен).

Синтаксис

Заявления возврата бывают разных форм. Наиболее распространены следующие синтаксисы:

ЯзыкЗаявление о возвратеЕсли значение опущено, возврат
Ада, Баш,[1] C, C ++, Ява, PHP, C #, JavaScript, D
возвращаться ценить;
в Bash значение выхода последней команды, выполненной в функции

в C[2] и C ++,[3] неопределенное поведение если функция возвращает значение

в PHP,[4] возвращается НОЛЬ

в Javascript,[5] возвращает значение неопределенный

в Java и C # не разрешено, если функция возвращает значение

БАЗОВЫЙ
ВОЗВРАЩАТЬСЯ
Лисп
(возвращаться ценить)
значение последнего утверждения
Perl, Рубин
возвращаться @значения;возвращаться $ значение;возвращаться;

или контекстная возвращаемая последовательность

значение последнего утверждения
PL / I
возврат (выражение); возврат;
неопределенное поведение если процедура объявлена ​​как возвращающая значение
Python
возвращаться ценить
Никто
Болтовня
^ ценить
Tcl
возвращатьсявозвращаться $ значениевозвращаться -ошибка кода "Сообщение об ошибке"

или более сложное сочетание опций

значение последнего утверждения
Visual Basic .NET
Возвращаться ценить
Windows PowerShell
возвращаться ценить;
объект
сборка x86
Ret
содержимое регистра eax (условно)

В некоторых языки ассемблера, например, что для Технология MOS 6502 используется мнемоника "RTS" (ReTurn from Subroutine).

Множественные операторы возврата

Языки с явным оператором возврата создают возможность использования нескольких операторов возврата в одной и той же функции. Вопрос о том, хорошо это или нет, остается спорным.

Сильные сторонники структурное программирование убедитесь, что каждая функция имеет один вход и один выход (SESE). Таким образом, утверждалось[6] что следует избегать использования явного оператора возврата, за исключением текстового конца подпрограммы, учитывая, что, когда он используется для «раннего возврата», он может страдать от тех же проблем, которые возникают для ИДТИ К утверждение. И наоборот, можно утверждать, что использование оператора return имеет смысл, когда альтернативой является более запутанный код, например, более глубокая вложенность, ухудшающая читаемость.

В своем учебнике 2004 г. Дэвид Ватт пишет, что «часто желательны потоки управления с одним входом и несколькими выходами». Используя концепцию Теннента секвенсор Ватт единообразно описывает конструкции потока управления, встречающиеся в современных языках программирования, и пытается объяснить, почему определенные типы секвенсоров предпочтительнее других в контексте потоков управления с несколькими выходами. Ватт пишет, что неограниченные переходы (секвенсоры перехода) - это плохо, потому что назначение перехода не является самоочевидным для читателя программы, пока читатель не найдет и не изучит фактическую метку или адрес, являющийся целью перехода. Напротив, Уотт утверждает, что концептуальное предназначение секвенсора возврата ясно из его собственного контекста, без необходимости исследовать его назначение. Кроме того, Ватт пишет, что класс секвенсоров, известный как escape-последовательности, определяемый как «секвенсор, который завершает выполнение команды или процедуры, заключенной в текст», охватывает оба перерывы from циклы (включая многоуровневые разрывы) и операторы возврата. Ватт также отмечает, что, хотя секвенсоры переходов (gotos) были в некоторой степени ограничены в таких языках, как C, где цель должна быть внутри локального блока или охватывающим внешним блоком, одного этого ограничения недостаточно, чтобы сделать намерение gotos в C самим собой. -описание и чтобы они все еще могли производить »код спагетти ". Watt также исследует, чем секвенсоры исключений отличаются от секвенсоров перехода и перехода; подробнее об этом читайте в статье структурное программирование.[7]

Согласно эмпирическим исследованиям, цитируемым Эрик С. Робертс, студенты-программисты испытывали трудности с формулированием правильных решений нескольких простых задач на таком языке, как Паскаль, что не позволяет использовать несколько точек выхода. Что касается проблемы написания функции для линейного поиска элемента в массиве, исследование 1980 года Генри Шапиро (цитируется Робертсом) показало, что при использовании только управляющих структур, предоставленных Паскалем, правильное решение было дано только 20% испытуемых. , в то время как ни один субъект не написал неправильный код для этой проблемы, если разрешено написать возврат из середины цикла.[8]

Другие, в том числе Кент Бек и Мартин Фаулер утверждать, что один или несколько охранные оговорки - условные операторы возврата "раннего выхода" в начале функции - часто делают функцию более легкой для чтения, чем альтернативу.[9][10][11][12]

Самая распространенная проблема при раннем выходе состоит в том, что операторы очистки или final не выполняются - например, выделенная память не является нераспределенной или открытые файлы не закрываются, что вызывает утечки. Это необходимо делать на каждом сайте возврата, который является хрупким и может легко привести к ошибкам. Например, в более поздней разработке разработчик мог упустить из виду оператор return и действие, которое должно быть выполнено в конце подпрограммы (например, след заявление) может выполняться не во всех случаях. Языки без оператора возврата, например стандартные Паскаль нет этой проблемы. Некоторые языки, такие как C ++ и Python, используют концепции, которые позволяют действиям выполняться автоматически при возврате (или выбросе исключения), что смягчает некоторые из этих проблем - они часто известны как «попробуй / наконец» или аналогичные. Функциональность, подобная этим предложениям "finally", может быть реализована с помощью перехода к единственной точке возврата подпрограммы. Альтернативным решением является использование обычного раскручивания стека (освобождение переменных) при выходе из функции для освобождения ресурсов, например, с помощью деструкторов для локальных переменных или аналогичных механизмов, таких как оператор «with» в Python.

Некоторые ранние реализации языков, такие как исходный Pascal и C, ограничивали типы, которые могут быть возвращены функцией (например, не поддерживая записывать или же структура типы), чтобы упростить их компиляторы.

В Ява - и похожие языки, смоделированные на его основе, например JavaScript - можно выполнить код даже после оператора возврата, потому что наконец-то блок структура try-catch всегда выполняется. Так что если возвращаться заявление находится где-то внутри пытаться или же ловить блокирует код внутри наконец-то (если добавлен) будет выполнен. Можно даже изменить возвращаемое значение непримитивного типа (свойство уже возвращенного объекта), потому что выход также происходит впоследствии.[13]

Заявления о доходности

Двоюродный брат, чтобы вернуть заявления отчеты о доходности: где возврат вызывает субрутина для прекратить, урожай вызывает coрутина к приостановить. Позднее сопрограмма продолжит работу с того места, где она была приостановлена, если ее вызовут снова. Реализация сопрограмм значительно сложнее, чем подпрограмм, и поэтому операторы yield менее распространены, чем операторы return, но они встречаются во многих языках.

Последовательности вызова / возврата

В зависимости от набора инструкций оборудования возможен ряд возможных последовательностей вызова / возврата, включая следующие:

  1. В ВЫЗОВ инструкция подталкивает адрес следующий инструкция в стеке и переходит к указанному адресу. В ВОЗВРАЩАТЬСЯ Инструкция выталкивает адрес возврата из стека в указатель инструкции, и выполнение возобновляется с этого адреса. (Примеры x86, PDP-11)
  2. В ВЫЗОВ инструкция размещает адрес следующий инструкция в реестре и переход по указанному адресу. В ВОЗВРАЩАТЬСЯ Последовательность команд помещает адрес возврата из регистра в указатель команд, и выполнение возобновляется с этого адреса. (Пример IBM System / 360)
  3. В ВЫЗОВ инструкция размещает адрес следующий (или же Текущий) инструкция в ячейке памяти по адресу вызова и переходит на указанный адрес + 1. В ВОЗВРАЩАТЬСЯ последовательность команд переходит к адресу возврата с помощью косвенный перейти к первой инструкции подпрограммы. (Примеры IBM 1130, SDS9XX)

Смотрите также

Рекомендации

  1. ^ в Bash могут быть возвращены только целые числа в диапазоне 0-255: http://tldp.org/LDP/abs/html/complexfunct.html#RETURNREF
  2. ^ https://msdn.microsoft.com/en-us/library/sta56yeb.aspx MSDN: выражение возврата (C)
  3. ^ https://msdn.microsoft.com/en-us/library/k68ktdwf.aspx MSDN: инструкция возврата (C ++)
  4. ^ «PHP: возврат - Вручную». Руководство по PHP. Группа PHP. Получено 26 марта 2013.
  5. ^ «Возврат - Javascript». Справочник по MDN Javascript. Сеть разработчиков Mozilla. Получено 27 марта 2013.
  6. ^ Примечания по C ++: Заявление о возврате функции
  7. ^ Дэвид Энтони Уотт; Уильям Финдли (2004). Концепции проектирования языков программирования. Джон Вили и сыновья. С. 215–221. ISBN  978-0-470-85320-7.
  8. ^ Робертс, Э. [1995] «Выходы из цикла и структурное программирование: возобновление дискуссии», Бюллетень ACM SIGCSE, (27) 1: 268–272.
  9. ^ Мартин Фаулер, Кент Бек, Джон Брант, Уильям Опдайк, Дон Робертс.«Рефакторинг: улучшение дизайна существующего кода (электронная книга Google)».section «Заменить вложенные условия на защитные предложения» .2012.p. 237, стр. 250. цитата: «... менталитет одной точки выхода ... Я не следую правилу об одной точке выхода из метода».
  10. ^ Кент Бек.«Шаблоны реализации».2007. «Глава 7: Поведение», раздел «Предохранительная оговорка».
  11. ^ «Множественные операторы возврата»
  12. ^ Фред Шварц.«Заявления о возвращении и фантазия о единственном выходе».
  13. ^ Последний блок, Учебники по Java