Как Вы возвращаете два значения из отдельного метода?

ПУСТОЙ УКАЗАТЕЛЬ является просто определением препроцессора. Это находится в stdio.h. Как правило, только безумный человек переопределил бы его, но это возможно. Пример:

#include <stdio.h>
#ifdef NULL
#undef NULL
#define NULL 1
#endif

void main()
{

        if (NULL)
                printf("NULL is true\n");
        else
                printf("NULL is false\n");
}

Этот код распечатает "ПУСТОЙ УКАЗАТЕЛЬ, верно". Попробуйте его, если Вы не верите мне. Ваш компилятор даже не мог бы предупредить Вас, что Вы делаете что-то странное.

15
задан 2 revs, 2 users 95% 23 September 2009 в 21:03
поделиться

22 ответа

Это не полностью зависит от языка: в Лиспе вы можете фактически вернуть любое количество значений из функции, включая (но не ограничиваясь) none, one, two, ...

(defun returns-two-values ()
  (values 1 2))

То же самое верно и для Схема и Дилана. В Python я бы фактически использовал кортеж, содержащий 2 значения, например

def returns_two_values():
   return (1, 2)

. Как отмечали другие, вы можете вернуть несколько значений, используя параметры out в C #. В C ++ вы должны использовать ссылки.

void 
returns_two_values(int& v1, int& v2)
{
    v1 = 1; v2 = 2;
}

В C ваш метод будет принимать указатели на места, где ваша функция должна хранить значения результатов.

void 
returns_two_values(int* v1, int* v2)
{
    *v1 = 1; *v2 = 2;
}

Для Java я обычно использую либо выделенный класс, либо довольно общий маленький помощник (в настоящее время их два в моя личная библиотека "общего пользования": Pair и Triple , оба не более чем простые неизменяемые контейнеры для 2 соотв.

15
ответ дан 1 December 2019 в 00:05
поделиться

Haskell также позволяет несколько возвращаемых значений с использованием встроенных кортежей:

sumAndDifference        :: Int -> Int -> (Int, Int)
sumAndDifference x y    = (x + y, x - y)

> let (s, d) = sumAndDifference 3 5 in s * d
-16

Поскольку это чистый язык, варианты 1 и 2 не допускаются.

Даже при использовании монады состояний возвращаемое значение содержит (по крайней мере, концептуально) пакет со всеми соответствующими состояниями, включая любые изменения только что сделанной функции. Это просто причудливое соглашение о передаче этого состояния через последовательность операций.

0
ответ дан 1 December 2019 в 00:05
поделиться

Для описанной вами ситуации, извлекая два поля из одной таблицы, соответствующий ответ - №4, учитывая, что два свойства (поля) одной и той же сущности (таблицы) будут демонстрировать сильную связанность.

Ваше беспокойство по поводу того, что «создание класса только с целью возврата может сбить с толку» вероятно, не так уж и реалистично. Если ваше приложение нетривиально, вам, вероятно, все равно придется повторно использовать этот класс / объект в другом месте.

0
ответ дан 1 December 2019 в 00:05
поделиться

You should also consider whether the design of your method is primarily returning a single value, and you are getting another value for reference along with it, or if you really have a single returnable thing like first name - last name.

For instance, you might have an inventory module that queries the number of widgets you have in inventory. The return value you want to give is the actual number of widgets.. However, you may also want to record how often someone is querying inventory and return the number of queries so far. In that case it can be tempting to return both values together. However, remember that you have class vars availabe for storing data, so you can store an internal query count, and not return it every time, then use a second method call to retrieve the related value. Only group the two values together if they are truly related. If they are not, use separate methods to retrieve them separately.

0
ответ дан 1 December 2019 в 00:05
поделиться

Мой выбор №4. Определите ссылочный параметр в своей функции. Этот указатель ссылается на объект значения.

В PHP:

class TwoValuesVO {
  public $expectedOne;
  public $expectedTwo;
}

/* parameter $_vo references to a TwoValuesVO instance */
function twoValues( & $_vo ) {
  $vo->expectedOne = 1;
  $vo->expectedTwo = 2;
}

В Java:

class TwoValuesVO {
  public int expectedOne;
  public int expectedTwo;
}

class TwoValuesTest {
  void twoValues( TwoValuesVO vo ) {
    vo.expectedOne = 1;
    vo.expectedTwo = 2;
  }
}
0
ответ дан 1 December 2019 в 00:05
поделиться

Используйте std :: vector, QList или какой-нибудь контейнер управляемой библиотеки для хранения того количества X, которое вы хотите вернуть:

QList<X> getMultipleItems()
{
  QList<X> returnValue;
  for (int i = 0; i < countOfItems; ++i)
  {
    returnValue.push_back(<your data here>);
  }
  return returnValue;
}
0
ответ дан 1 December 2019 в 00:05
поделиться

Как ни больно мне это делать, я нахожу наиболее удобочитаемый способ вернуть несколько значений в PHP (с которым я работаю, в основном ) использует (многомерный) массив, например:

function doStuff($someThing)
{
    // do stuff
    $status  = 1;
    $message = 'it worked, good job';

    return array('status' => $status, 'message' => $message);
}

Не очень красиво, но он работает, и понять, что происходит, не так уж сложно.

0
ответ дан 1 December 2019 в 00:05
поделиться

Обычно я использую кортежи. В основном я работаю на C #, и на нем очень легко создавать универсальные конструкции кортежей. Я предполагаю, что это было бы очень похоже для большинства языков, у которых есть обобщения. Кстати, 1 - ужасная идея, а 3 работает только тогда, когда вы получаете два возвращаемых значения одного и того же типа, если только вы не работаете на языке, где все происходит от одного и того же базового типа (то есть объекта). 2 и 4 - тоже хороший выбор. 2 априори не вызывает никаких побочных эффектов, он просто громоздкий.

0
ответ дан 1 December 2019 в 00:05
поделиться

Используйте параметры var / out или передавайте переменные по ссылке, а не по значению. В Delphi:

function ReturnTwoValues(out Param1: Integer):Integer;
begin
  Param1 := 10;
  Result := 20;
end;

Если вы используете var вместо out, вы можете предварительно инициализировать параметр.

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

0
ответ дан 1 December 2019 в 00:05
поделиться

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

В вашем примере упоминается строка или набор строк из SQL-запроса. Тогда вы должны быть готовы иметь дело с ними как с объектами или массивами, что предлагает соответствующий ответ на ваш вопрос.

1
ответ дан 1 December 2019 в 00:05
поделиться

When your in a situation where you need to return two things in a single method, what is the best approach?

It depends on WHY you are returning two things. Basically, as everyone here seems to agree, #2 and #4 are the two best answers...

I understand the philosophy that a method should do one thing only, but say you have a method that runs a database select and you need to pull two columns. I'm assuming you only хочу пройти через базу данных результат устанавливается один раз, но вы хотите вернуть данные в два столбца.

Если две части данных из базы данных связаны, например, имя и фамилия клиента, я действительно все равно буду считать, что это делает «одно дело». С другой стороны, предположим, что вы придумали странный оператор SELECT, который возвращает общий объем продаж вашей компании на заданную дату, а также читает имя клиента, совершившего первую продажу на сегодняшний день. Здесь вы делаете две несвязанные друг с другом вещи! If it's really true that performance of this strange SELECT statement is much better than doing two SELECT statements for the two different pieces of data, and both pieces of data really are needed on a frequent basis (so that the entire application would be slower if you didn't do it that way), then using this strange SELECT might be a good idea - but you better be prepared to demonstrate why your way really makes a difference in perceived response time.

The options I have come up with:

1 Use global variables to hold returns. I personally try and avoid globals where I can.

There are some situations where creating a global is the right thing to do. But "returning two things from a function" is not one of those situations. Doing it for this purpose is just a Bad Idea.

2 Pass in two empty variables as parameters then assign the variables inside the method, which now is a void.

Yes, that's usually the best idea. This is exactly why "by reference" (or "output", depending on which language you're using) parameters exist.

I don't like the idea of methods that have a side effects.

Good theory, but you can take it too far. What would be the point of calling SaveCustomer() if that method didn't have a side-effect of saving the customer's data? Под параметрами ссылки понимаются параметры, содержащие возвращаемые данные.

3 Возвращает коллекцию, содержащую две переменные. Это может привести к путанице в коде.

Верно. Например, не имело бы смысла возвращать массив, в котором элемент 0 был именем, а элемент 1 - фамилией. Это было бы плохой идеей.

4 Создайте контейнерный класс для хранения двойного возврата. Это больше самодокументируется, чем коллекция, содержащая другие коллекции, но кажется, что создание класса только с целью возврата может сбить с толку.

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

1
ответ дан 1 December 2019 в 00:05
поделиться

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

И если вы сегодня возвращаете две вещи из этих двух столбцов, завтра вам может понадобиться третья. Поддерживать настраиваемый объект будет намного проще, чем любой другой вариант.

1
ответ дан 1 December 2019 в 00:05
поделиться
  1. Некоторые языки делают работу №3 естественной и простой. Пример: Perl. "return ($ a, $ b);". То же самое.

  2. За исключением этого, проверьте, есть ли в вашем языке коллекция, подходящая для данной задачи, например, пара / кортеж в C ++

  3. Запретив это, создайте класс пары / кортеж и / или коллекцию и повторно используйте ее, особенно если ваш язык поддерживает шаблоны.

1
ответ дан 1 December 2019 в 00:05
поделиться

Лично я стараюсь использовать языки, которые позволяют функциям возвращать нечто большее, чем простое целочисленное значение.

Во-первых, вы должны различать, что вы хотите: возврат произвольной длины или фиксированной длины return.

Если вы хотите, чтобы ваш метод возвращал произвольное количество аргументов, вам следует придерживаться возврата из коллекции. Потому что коллекции - на каком бы языке вы ни были - специально привязаны для выполнения такой задачи.

Но иногда вам просто нужно вернуть два значения. Как возврат двух значений - когда вы уверены, что это всегда два значения - отличается от возврата одного значения? Я говорю, нет никаких различий! А современные языки, включая perl, ruby, C ++, python, ocaml и т. Д., Позволяют функции возвращать кортежи, либо встроенные, либо как сторонний синтаксический сахар (да, я говорю о boost :: кортеж ). Похоже, что:

tuple<int, int, double> add_multiply_divide(int a, int b) {
  return make_tuple(a+b, a*b, double(a)/double(b));
}

Указание «выходного параметра», на мой взгляд, используется чрезмерно из-за ограничений старых языков и парадигм, изученных в те дни. Но есть еще много случаев, когда его можно использовать (если ваш метод должен изменить объект, переданный в качестве параметра, этот объект не является классом, содержащим метод).

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

Но есть еще много случаев, когда его можно использовать (если ваш метод должен изменить объект, переданный в качестве параметра, этот объект не является классом, содержащим метод).

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

Но все еще есть много случаев, когда его можно использовать (если ваш метод должен изменить объект, переданный в качестве параметра, этот объект не является классом, содержащим метод).

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

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

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

2
ответ дан 1 December 2019 в 00:05
поделиться

Python (как и Lisp) также позволяет возвращать любое количество значения из функции, включая (но не ограничиваясь ими) нет, один, два

def quadcube (x):
     return x**2, x**3

a, b = quadcube(3)
2
ответ дан 1 December 2019 в 00:05
поделиться

Я думаю, что наиболее предпочтительным подходом является создание контейнера (будь то класс или структура - если вы не хотите создавать для этого отдельный класс, структура - это способ go), в котором будут храниться все возвращаемые параметры.

3
ответ дан 1 December 2019 в 00:05
поделиться

В мире C / C ++ довольно распространено передавать две переменные по ссылке ( пример , ваш № 2).

3
ответ дан 1 December 2019 в 00:05
поделиться

Я думаю, все зависит от сценария.

Думая, исходя из менталитета C #:

1: Я бы избегал глобальных переменных в качестве решения этой проблемы, так как это считается плохим практика.

4: Если два возвращаемых значения однозначно связаны друг с другом каким-либо образом или в такой форме, что они могут существовать как отдельный объект, то вы можете вернуть один объект, содержащий два значения. Если этот объект разрабатывается и используется только для типа возвращаемого значения этого метода, то это, вероятно, не лучшее решение.

3: Коллекция - отличный вариант, если возвращаемые значения имеют тот же тип и могут рассматриваться как Коллекция. Однако, если в конкретном примере требуется 2 элемента, и каждый элемент является «собственным» -> возможно, один представляет начало чего-то, а другой - конец, и возвращенные элементы не используются взаимозаменяемо, тогда это может быть не лучший вариант.

2: Мне больше всего нравится этот вариант, если 4 и 3 не имеют смысла для вашего сценария. Как указано в пункте 3, если вы хотите получить два объекта, которые представляют собой начало и конец чего-либо. Затем я бы использовал параметры по ссылке (или параметры out, опять же, в зависимости от того, как все это используется). Таким образом, ваши параметры могут явно определять свое назначение: MethodCall (ссылка на объект StartObject, ссылка на объект EndObject)

все используются). Таким образом, ваши параметры могут явно определять свое назначение: MethodCall (ссылка на объект StartObject, ссылка на объект EndObject)

все используются). Таким образом, ваши параметры могут явно определять свое назначение: MethodCall (ссылка на объект StartObject, ссылка на объект EndObject)

3
ответ дан 1 December 2019 в 00:05
поделиться

Не мои собственные мысли (мысли дяди Боба):

Если есть связь между этими двумя переменными - я слышал, он сказал, что вам не хватает класс, где эти два поля. (Он сказал то же самое о функциях с длинными списками параметров.)

С другой стороны, если нет согласованности, тогда функция выполняет более одного действия.

12
ответ дан 1 December 2019 в 00:05
поделиться

Я бы создал объекты передачи данных. Если это группа информации (имя и фамилия), я бы создал класс Name и вернул бы его. # 4 - это то, что нужно. Похоже, что впереди нужно еще поработать (а это так), но позже я проясню это.

Если это список записей (строк в базе данных), я бы вернул некую коллекцию.

Я бы никогда не использовал глобальные переменные, если приложение не является тривиальным.

14
ответ дан 1 December 2019 в 00:05
поделиться

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

Объекты вместо значений функции в языках без первоклассных функций.

0
ответ дан 1 December 2019 в 00:05
поделиться

Обычно я выбираю подход №4, так как я предпочитаю ясность в том, что функция производит или вычисляет возвращаемое значение (а не параметры byref). Кроме того, он обеспечивает довольно «функциональный» стиль в потоке программы.

Недостатком варианта №4 с универсальными классами кортежей является то, что он не намного лучше, чем возврат коллекции (единственное преимущество - безопасность типов).

public IList CalculateStuffCollection(int arg1, int arg2)
public Tuple<int, int> CalculateStuffType(int arg1, int arg2)

var resultCollection = CalculateStuffCollection(1,2);
var resultTuple = CalculateStuffTuple(1,2);

resultCollection[0]    // Was it index 0 or 1 I wanted? 
resultTuple.A          // Was it A or B I wanted?

] Мне нужен язык, который позволил бы мне возвращать неизменяемый кортеж именованных переменных (аналогичный словарю, но неизменяемый, типизированный и статически проверенный). Но, к сожалению, такая опция недоступна для меня в мире VB.NET, она может быть где-то еще.

Мне не нравится вариант №2, потому что он нарушает этот «функциональный» стиль и заставляет вас вернуться в процедурный мир (когда часто я не

0
ответ дан 1 December 2019 в 00:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: