В предыдущем видео мы обсудили как же вернуть один объект из функции. Конечно через return. Но что же делать, если вы хотите вернуть из функции несколько объектов, возможно разных типов. На самом деле мы это уже обсуждали в начале второго курса, и на эту тему даже была задача трекер задач. В этой задаче нужно было реализовать, в том числе, среди прочих, метод PerformPersonTasks, который возвращает два словаря задач. Задачи, которые в данный момент оказались затронуты и те, которые оказались нетронутыми. Это мы делали с помощью кортежа, кортеж из двух объектов типа Tasks info, это делалось максимально просто вот здесь, просто tuple, и в самом методе мы в конце писали return и два объекта, которые мы возвращаем в фигурных скобках. Все просто и понятно. Почему это удобно? Потому что мы могли при вызове этой функцией использовать structured binding, то есть написать, что updated tasks, untouched tasks вот такие две переменные сейчас заводятся и инициализируются с помощью вызова функции, как у нас назывался класс, класс назывался Team Tasks. Ну, то ест tasks.performPersonTasks, с какими-то аргументами. Именно structured binding позволяют нам здесь использовать возврат с помощью кортежа из нескольких объектов, причем, что еще хорошо, что даже до structured binding, если у вас эти переменные уже есть, они как-то объявлены, Tasks Info updated Tasks и untouched Tasks, даже когда не было structured binding мы могли использовать tie, вызвали функцию tie от этих двух переменных и этому tai присвоили результат вызова метода performPersonTasks. Но как правило, конечно, вы используете structured binding, потому что этих переменных у вас еще нет. Это все хорошо и замечательно, но давайте посмотрим на этот код с точки зрения его понятности. Если вы возвращаете из функции наборы объектов совершенно разных типов, и по ним совершенно понятно, какой из них что означает, например, если есть функция ComputeCoast и она возвращает int и некий объект с типом Currency Type, наверно понятно, что это собственно код, который мы хотели вычислить, а Currency Type, это валюта, в которой это цена у нас хранится. Вот к такой сигнатуре функции вопросов не возникает. Если же у нас performTasks возвращает 2 Tasks Info, то в принципе из контекста не очень понятно, что означает первый Tasks Info и второе, чем они вообще отличаются. И для этих случаев удобно вместо пар и кортежой с непонятными названиями полей, использовать структуры. Давайте я это продемонстрирую на том же самом примере и заведу структуру для результата метода performPersonTasks. Назову её PerformResult, например, и там будет просто два поля типа Tasks Info, uodated tasks, и Tasks Info untouched. И здесь я напишу, что возвращаю performResult, и сразу понятно, что я возвращаю updated Task и untouched Tasks, потому что у меня вот рядом определение структуры. У меня никак не меняется return выражения, и что самое приятное в structured binding, что они умеют распаковывать и структуру тоже, поэтому вот это выражение никак менять не придется. Не бойтесь того, что компилятор здесь подчеркивает это выражение, просто пока не знает про structured binding. Хорошо, что еще можно сказать про возврат нескольких объектов из функции? Не боитесь ли вы, что в выражениях у вас случаться копирования? Конечно, я вас уже почти убедил, что в return все будет хорошо, но здесь есть маленький нюанс, который были введены в коде тоже. Если при возврате одной переменной из функций вас спасал NameReturnValueOptimisation, то когда вы возвращаете набор переменных, объединяя их в фигурные скобки, чтобы у вас получилась пара или кортеж, то есть здесь никакого NameReturnValueOptimisation не будет, и вам надо явно вызвать move от этих переменных при передаче в конструктор пары или кортежа. Это не очень удобно, но плюсы возврата через return и затем связанные с помощью structured binding этот минус перевешивают. Итак, подведем итоги, несколько объектов из функций возвращают через return, при этом принять их можно снаружи с помощью structured binding в квадратных скобках или функцией tie, при этом пары и картежи, это конечно хорошо, они умеют распаковываться, но следите за понятностью этих объектов, и если вы чувствуете что есть риски, то заводите структуру с понятными названиями полей, она тоже умеет распаковываться. При этом следите за тем, чтобы у вас не случилось лишних копирований при передаче переменных, которые вы хотите вернуть в конструктор пары или кортежа. Далее мы обсудим интересные случаи возврата объектов из функции. Когда вы хотите вернуть объект или ничего, или вернуть объект какого-то одного из двух типов.