How do you return two values from a single method?

2019-01-19 10:52发布

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

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 want to traverse through the database result set once, but you want to return two columns worth of data.

The options I have come up with:

  1. Use global variables to hold returns. I personally try and avoid globals where I can.
  2. Pass in two empty variables as parameters then assign the variables inside the method, which now is a void. I don't like the idea of methods that have a side effects.
  3. Return a collection that contains two variables. This can lead to confusing code.
  4. Build a container class to hold the double return. This is more self-documenting then a collection containing other collections, but it seems like it might be confusing to create a class just for the purpose of a return.

22条回答
三岁会撩人
2楼-- · 2019-01-19 11:43

Use std::vector, QList, or some managed library container to hold however many X you want to return:

QList<X> getMultipleItems()
{
  QList<X> returnValue;
  for (int i = 0; i < countOfItems; ++i)
  {
    returnValue.push_back(<your data here>);
  }
  return returnValue;
}
查看更多
叛逆
3楼-- · 2019-01-19 11:43

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.

查看更多
狗以群分
4楼-- · 2019-01-19 11:46
  1. Some languages make doing #3 native and easy. Example: Perl. "return ($a, $b);". Ditto Lisp.

  2. Barring that, check if your language has a collection suited to the task, ala pair/tuple in C++

  3. Barring that, create a pair/tuple class and/or collection and re-use it, especially if your language supports templating.

查看更多
叛逆
5楼-- · 2019-01-19 11:46

I will usually opt for approach #4 as I prefer the clarity of knowing what the function produces or calculate is it's return value (rather than byref parameters). Also, it lends to a rather "functional" style in program flow.

The disadvantage of option #4 with generic tuple classes is it isn't much better than returning a collection (the only gain is type safety).

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?

I would like a language that allowed me to return an immutable tuple of named variables (similar to a dictionary, but immutable, typesafe and statically checked). But, sadly, such an option isn't available to me in the world of VB.NET, it may be elsewhere.

I dislike option #2 because it breaks that "functional" style and forces you back into a procedural world (when often I don't want to do that just to call a simple method like TryParse).

查看更多
Luminary・发光体
6楼-- · 2019-01-19 11:47

Haskell also allows multiple return values using built in tuples:

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

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

Being a pure language, options 1 and 2 are not allowed.

Even using a state monad, the return value contains (at least conceptually) a bag of all relevant state, including any changes the function just made. It's just a fancy convention for passing that state through a sequence of operations.

查看更多
Deceive 欺骗
7楼-- · 2019-01-19 11:49

My choice is #4. Define a reference parameter in your function. That pointer references to a Value Object.

In PHP:

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

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

In Java:

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

class TwoValuesTest {
  void twoValues( TwoValuesVO vo ) {
    vo.expectedOne = 1;
    vo.expectedTwo = 2;
  }
}
查看更多
登录 后发表回答