Элегантные способы вернуть несколько значений из функции - PullRequest
27 голосов
/ 05 февраля 2009

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

Типичные решения - создать struct или простые старые данные class и вернуть их или передать хотя бы некоторые параметры по ссылке или указателю вместо возврата их.

Использование ссылок / указателей довольно неловко, потому что оно основано на побочных эффектах и ​​означает, что вам нужно передать еще один параметр.

Решение класса / структуры также ИМХО довольно неловко, потому что в результате вы получаете миллион маленьких классов / структур, которые используются только для возврата значений из функций, создавая ненужный беспорядок и многословие.

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

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

a, b = foo(c)  # a and b are regular variables.
myTuple = foo(c)  # myTuple is a tuple of (a, b)

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

Ответы [ 14 ]

0 голосов
/ 05 апреля 2012

Вот моя идея Ruby вернуть специальное значение, которое выглядит и действует как скаляр, но на самом деле имеет скрытые атрибуты:

https://gist.github.com/2305169

0 голосов
/ 02 февраля 2011

Кстати, Scala может возвращать несколько значений следующим образом (вставлено из сеанса интерпретатора):

scala> def return2 = (1,2)
return2: (Int, Int)

scala> val (a1,a2) = return2
a1: Int = 1
a2: Int = 2

Это особый случай использования сопоставления с образцом для назначения .

0 голосов
/ 02 июля 2010

с #

public struct tStruct
{
    int x;
    int y;
    string text;
    public tStruct(int nx, int ny, string stext)
    {
         this.x = nx;
         this.y = ny;
         this.text = stext;
    }
}

public tStruct YourFunction()
{
    return new tStruct(50, 100, "hello world");
}

public void YourPrintFunction(string sMessage)
{
    Console.WriteLine(sMessage);
}

в Луа звоните

MyVar = YourFunction();
YourPrintfFunction(MyVar.x);
YourPrintfFunction(MyVar.y);
YourPrintfFunction(MyVar.text);

Выход: 50 100 Привет, мир

Пол

0 голосов
/ 05 февраля 2009

В C++ вы можете передать контейнер в функцию, чтобы функция могла заполнить его:

void getValues(std::vector<int>* result){
  result->push_back(2);
  result->push_back(6);
  result->push_back(73);
}

Вы также можете сделать так, чтобы функция возвращала умный указатель (используйте shared_ptr) на vector:

boost::shared_ptr< std::vector<int> > getValues(){
  boost::shared_ptr< std::vector<int> > vec(new std::vector<int>(3));
  (*vec)[0] = 2;
  (*vec)[1] = 6;
  (*vec)[2] = 73;
  return vec; 
}
...