Возврат запроса из метода
В этом примере показан способ возврата запроса из метода в качестве возвращаемого значения и параметра out .
Объекты запроса являются составляемыми, что означает возможность возврата запроса из метода. Объекты, представляющие запросы, не сохраняют результирующую коллекцию, а сохраняют действия, необходимые для получения результатов. Преимущество возвращения объектов запроса заключается в том, что их можно комбинировать или изменять. Поэтому любое возвращаемое значение или параметр out метода, который возвращает запрос, должны также иметь этот тип. Если метод материализует запрос в конкретный тип List или Array, считается, что он должен возвращать результаты запроса, а не сам запрос. Переменную запроса, возвращаемую из метода, можно формировать или изменять.
Пример
В следующем примере первый метод QueryMethod1 возвращает запрос в качестве возвращаемого значения, а второй метод QueryMethod2 возвращает запрос в качестве out параметра ( returnQ в примере). Обратите внимание, что в обоих случаях возвращается запрос, а не его результаты.
IEnumerable QueryMethod1(int[] ints) => from i in ints where i > 4 select i.ToString(); void QueryMethod2(int[] ints, out IEnumerable returnQ) => returnQ = from i in ints where i < 4 select i.ToString(); int[] nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; var myQuery1 = QueryMethod1(nums);
Запрос myQuery1 выполняется в следующем цикле foreach.
foreach (var s in myQuery1)
Наведите указатель myQuery1 мыши на указатель мыши, чтобы просмотреть его тип.
Вы также можете выполнить запрос, возвращаемый напрямую QueryMethod1 , без использования myQuery1 .
foreach (var s in QueryMethod1(nums))
Наведите указатель мыши на вызов, чтобы QueryMethod1 просмотреть тип возвращаемого значения.
QueryMethod2 возвращает запрос в качестве значения параметра out:
QueryMethod2(nums, out IEnumerable myQuery2); // Execute the returned query. foreach (var s in myQuery2)
Запрос можно изменить с помощью композиции запросов. В этом случае предыдущий объект запроса используется для создания нового объекта запроса. Этот новый объект возвращает результаты, отличные от исходного объекта запроса.
myQuery1 = from item in myQuery1 orderby item descending select item; // Execute the modified query. Console.WriteLine("\nResults of executing modified myQuery1:"); foreach (var s in myQuery1)
См. также
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Как вернуть два значения из метода c
Функция в C может возвращать только одно значение. Тем не менее, что если нам надо получить из функции сразу несколько значений? В этом случае мы можем использовать разные подходы. Основные из них - возвращение комплексного объекта, который инкапсулирует отдельные значения, либо использование выходных параметров.
Объединение возвращаемых значений
Наиболее простой способ возвратить из функции несколько значений - это определить структуру для хранения этих значений и возвратить ее. Например, нам надо получить из массива минимальное и максимальное значения. Для этого мы могли определить функцию, которая возвращает структуру с двумя значениями:
#include #include typedef struct < int min; int max; >MinMax; MinMax getMinMax(int* array, size_t length) < assert(length >1 && "Array length is invalid"); MinMax result; result.min = array[0]; result.max = array[0]; for(size_t i = 0; i < length; i++) < if(array[i] < result.min) result.min = array[i]; if(array[i] >result.max) result.max = array[i]; > return result; > int main(void) < int array[] = ; size_t length = sizeof(array) / sizeof(int); MinMax data = getMinMax(array, length); printf("min=%d\n", data.min); // min=2 printf("max=%d\n", data.max); // max=9 >
Здесь для возвращения из функции минимального и максимального значения массива определена структура MinMax, которую возвращает функция getMinMax. Это наиболее простой и очевидный способ возвращения нескольких значений. Однако он имеет свои минусы. Прежде всего нам надо специально определять структуру под возвращаемые значения. Во-вторых, при возвращении структуры происходит копирование ее значений в стеке, что увеличивает объем потребляемой памяти.
Выходные параметры
Другой способ возвратить из функции несколько значений представляют выходные параметры (out-параметры). Язык Си как таковой не имеет концепции выходных параметров функции (как например, C#), однако мы можем симулировать выходные параметры с помощью указателей:
#include #include void getMinMax(int* array, size_t length, int* min, int* max) < assert(length >1 && "Array length is invalid"); *min = array[0]; *max = array[0]; for(size_t i = 0; i < length; i++) < if(array[i] < *min) *min = array[i]; if(array[i] >*max) *max = array[i]; > > int main(void) < int array[] = ; size_t length = sizeof(array) / sizeof(int); int minVal = 0; int maxVal = 0; getMinMax(array, length, &minVal, &maxVal); printf("min=%d\n", minVal); printf("max=%d\n", maxVal); >
Общий механизм определения и передачи выходных параметров заключается в следующем. Во-первых, определяем в функции параметры-указатели:
void getMinMax(int* array, size_t length, int* min, int* max)
Здесь параметры-указатели min и max как представляют выходные параметры. Внутри функции нам не важны их начальные значения. Наоборот, функция устанавливает их значения.
При вызове функции определяются переменные, и их адреса передаются выходным параметрам:
int minVal = 0; int maxVal = 0; getMinMax(array, length, &minVal, &maxVal);
В данном случае выходным параметрам min и max передаются соответственно адреса переменных minVal и maxVal.
При использовании выходных параметров нам не обязательно определять дополнительные структуры. Мы избегаем изличнего копирования возвращаемых значений в стеке. Однако выходные параметры рахдувают определение функции, могут снизить ее читабельность, особенно когда таких параметров много.
Как вернуть два значения из метода c
Метод может возвращать значение, какой-либо результат. В примере выше были определены два метода, которые имели тип void . Методы с таким типом не возвращают никакого значения. Они просто выполняют некоторые действия.
Но методы также могут возвращать некоторое значение. Для этого применяется оператор return , после которого идет возвращаемое значение:
return возвращаемое значение;
Например, определим метод, который возвращает значение типа string :
string GetMessage()
Метод GetMessage имеет тип string , следовательно, он должен возвратить строку. Поэтому в теле метода используется оператор return , после которого указана возвращаемая строка.
При этом методы, которые в качестве возвращаемого типа имеют любой тип, кроме void , обязательно должны использовать оператор return для возвращения значения. Например, следующее определение метода некорректно:
string GetMessage()
Также между возвращаемым типом метода и возвращаемым значением после оператора return должно быть соответствие. Например, в следующем случае возвращаемый тип - string , но метод возвращает число (тип int), поэтому такое определение метода некорректно:
string GetMessage() < return 3; // Ошибка! Метод должен возвращать строку, а не число >
Результат методов, который возвращают значение, мы можем присвоить переменным или использовать иным образом в программе:
string GetMessage() < return "Hello"; >string message = GetMessage(); // получаем результат метода в переменную message Console.WriteLine(message); // Hello
Метод GetMessage() возвращает значение типа string . Поэтому мы можем присвоить это значение какой-нибудь переменной типа string: string message = GetMessage();
Либо даже передать в качестве значения параметру другого метода:
string GetMessage() < return "Hello"; >void PrintMessage(string message) < Console.WriteLine(message); >PrintMessage(GetMessage());
В вызове PrintMessage(GetMessage()) сначада вызывается метод GetMessage() и его результат передается параметру message метода PrintMessage
После оператора return также можно указывать сложные выражения или вызовы других методов, которые возвращают определенный результат. Например, определим метод, который возвращает сумму чисел:
int Sum(int x, int y) < return x + y; >int result = Sum(10, 15); // 25 Console.WriteLine(result); // 25 Console.WriteLine(Sum(5, 6)); // 11
Метод Sum() имеет тип int , следовательно, он должен возвратить значение типа int - целое число. Поэтому в теле метода используется оператор return , после которого указано возвращаемое число (в данном случае результат суммы переменных x и y).
Сокращенная версия методов с результатом
Также мы можем сокращать методы, которые возвращают значение:
string GetMessage()
аналогичен следующему методу:
string GetMessage() => "hello";
int Sum(int x, int y)
аналогичен следующему методу:
int Sum(int x, int y) => x + y;
Выход из метода
Оператор return не только возвращает значение, но и производит выход из метода. Поэтому он должен определяться после остальных инструкций. Например:
string GetHello()
С точки зрения синтаксиса данный метод корректен, однако его инструкция Console.WriteLine("After return") не имеет смысла - она никогда не выполнится, так как до ее выполнения оператор return возвратит значение и произведет выход из метода.
Однако мы можем использовать оператор return и в методах с типом void . В этом случае после оператора return не ставится никакого возвращаемого значения (ведь метод ничего не возвращает). Типичная ситуация - в зависимости от опеределенных условий произвести выход из метода:
void PrintPerson(string name, int age) < if(age >120 || age < 1) < Console.WriteLine("Недопустимый возраст"); return; >Console.WriteLine($"Имя: Возраст: "); > PrintPerson("Tom", 37); // Имя: Tom Возраст: 37 PrintPerson("Dunkan", 1234); // Недопустимый возраст
Здесь метод PrintPerson() в качестве параметров принимает имя и возраст пользователя. Однако в методе вначале мы проверяем, соответствует ли возраст некоторому диапазону (меньше 120 и больше 0). Если возраст находится вне этого диапазона, то выводим сообщение о недопустимом возрасте и с помощью оператора return выходим из метода. После этого метод заканчивает свою работу.
Однако если возраст корректен, то выводим информацию о пользователе на консоль. Консольный вывод:
Имя: Tom Возраст: 37 Недопустимый возраст
Оператор return (C)
Оператор return завершает выполнение функции и возвращает управление вызывающей функции. Выполнение возобновляется в вызывающей функции в точке сразу после вызова. Оператор return может возвращать значение, передавая его вызывающей функции. Дополнительные сведения см. в статье Тип возвращаемого значения.
Синтаксис
jump-statement :
return expression необ. ;
Значение expression , если оно имеется, возвращается вызывающей функции. Если expression параметр опущен, возвращаемое значение функции не определено. Параметр "выражение", если он присутствует, вычисляется и преобразуется к типу, возвращаемому функцией. Если оператор return содержит выражение в функциях, имеющих тип возвращаемого значения void , то компилятор выдает предупреждение, а выражение не вычисляется.
Если в определении функции оператор return не указан, то после выполнения последнего оператора вызванной функции управление автоматически возвращается вызывающей функции. В этом случае возвращаемое значение вызванной функции не определено. Если функция имеет тип возвращаемого значения, отличный от void , это считается серьезной ошибкой и компилятор выводит предупреждающее диагностическое сообщение. Если функция имеет тип возвращаемого значения void , то такое поведение приемлемо, но может считаться плохим стилем. Чтобы ваше намерение было понятным, используйте простой оператор return .
В качестве лучшей методики разработки рекомендуется всегда указывать тип возвращаемого значения для ваших функций. Если возвращаемое значение не требуется, объявите функцию как имеющую тип возвращаемого значения void . Если тип возвращаемого значения не указан, компилятор C предполагает, что по умолчанию используется тип возвращаемого значения int .
Многие программисты используют круглые скобки для заключения expression аргумента return оператора . Однако использовать эти скобки в языке C необязательно.
Если компилятор обнаруживает операторы, размещенные после return , он может вывести предупреждающее диагностическое сообщение о недоступном для выполнения коде.
В функции main оператор return и выражение являются необязательными. То, что происходит с указанным возвращаемым значением, зависит от реализации. Только для Майкрософт:реализация C от Майкрософт возвращает значение выражения процессу, вызвавшему программу, например cmd.exe . Если выражение return не указано, среда выполнения C от Майкрософт возвращает значение, соответствующее успешному (0) или неудачному (ненулевое значение) выполнению.
Пример
В этом примере показана одна программа из нескольких частей. Она демонстрирует оператор return и использование его для завершения выполнения функции и, при необходимости, возврата какого-то значения.
// C_return_statement.c // Compile using: cl /W4 C_return_statement.c #include // for INT_MAX #include // for printf long long square( int value ) < // Cast one operand to long long to force the // expression to be evaluated as type long long. // Note that parentheses around the return expression // are allowed, but not required here. return ( value * (long long) value ); >
Функция square возвращает квадрат своего аргумента, используя более широкий тип для избежания арифметической ошибки. Только для систем Майкрософт: в реализации C от Майкрософт тип long long достаточно велик, чтобы вмещать произведение двух значений int без переполнения.
Скобки вокруг выражения return в функции square вычисляются как часть выражения, и использовать их в операторе return не требуется.
double ratio( int numerator, int denominator ) < // Cast one operand to double to force floating-point // division. Otherwise, integer division is used, // then the result is converted to the return type. return numerator / (double) denominator; >
Функция ratio возвращает частное двух int аргументов в виде значения double с плавающей запятой. Выражение return принудительно использует операцию с плавающей запятой путем приведения одного из операндов к типу double . В противном случае будет использоваться оператор целочисленного деления, а дробная часть будет потеряна.
void report_square( void ) < int value = INT_MAX; long long squared = 0LL; squared = square( value ); printf( "value = %d, squared = %lld\n", value, squared ); return; // Use an empty expression to return void. >
Функция report_square вызывает square со значением параметра INT_MAX — самым большим целым числом со знаком, которое помещается в int . Результат типа long long сохраняется в squared , а затем выдается в выводе. Функция report_square имеет тип возвращаемого значения void , поэтому она не содержит выражения в операторе return .
void report_ratio( int top, int bottom ) < double fraction = ratio( top, bottom ); printf( "%d / %d = %.16f\n", top, bottom, fraction ); // It's okay to have no return statement for functions // that have void return types. >
Функция report_ratio вызывает ratio со значениями параметров 1 и INT_MAX . Результат типа double сохраняется в fraction , а затем выдается в выводе. Функция report_ratio имеет тип возвращаемого значения void , поэтому явно возвращать значение не требуется. Выполнение report_ratio не дает результата и не возвращает вызывающей функции никакого значения.
int main()
Функция main вызывает две функции: report_square и report_ratio . Поскольку report_square не принимает параметров и возвращает void , результат не присваивается переменной. Аналогичным образом функция report_ratio возвращает void , поэтому ее возвращаемое значение тоже не сохраняется. После вызова каждой из этих функций выполнение продолжается в следующем операторе. Затем main возвращает значение 0 (обычно свидетельствующее об успешном выполнении), чтобы завершить программу.
Чтобы скомпилировать пример, создайте файл исходного кода с именем C_return_statement.c . Затем скопируйте весь пример кода в показанном здесь порядке. Сохраните файл и скомпилируйте его в окне Командной строки разработчика с помощью следующей команды:
cl /W4 C_return_statement.c
После этого, чтобы запустить пример кода, введите C_return_statement.exe в командной строке. Выходные данных в этом примере выглядят следующим образом:
value = 2147483647, squared = 4611686014132420609 1 / 2147483647 = 0.0000000004656613