Вернуть два и более значений из метода

105

Есть ли возможность вернуть несколько значений из метода? Что-то вроде этого:

def someMethod()
  return ["a", 10, SomeObject.new]
end

[a, b, c] = someMethod
демас
источник

Ответы:

160
def sumdiff(x, y)
  return x+y, x-y
end
#=> nil

sumdiff(3, 4)
#=> [7, -1]

a = sumdiff(3,4)
#=> [7, -1]
a
#=> [7, -1]

a,b=sumdiff(3,4)
#=> [7, -1]
a
#=> 7
b
#=> -1

a,b,c=sumdiff(3,4)
#=> [7, -1]
a
#=> 7
b
#=> -1
c
#=> nil
Адитья Мукхерджи
источник
Вы должны использовать форматирование кода, а не форматирование текста. Отступите строки на четыре пробела, и странности, вызванные подсказкой irb, >>исчезнут.
Крис Лутц,
4
Поскольку явный возврат считается неидиоматическим Ruby, вы также можете использовать неявный возврат, явно поместив возвращаемые значения в список:def foo_and_bar; ['foo', 'bar']; end
Деннис,
43

Ruby имеет ограниченную форму деструктурирующего связывания:

ary = [1, 2, 3, 4]
a, b, c = ary
p a # => 1
p b # => 2
p c # => 3

a, b, *c = ary
p c # => [3, 4]

a, b, c, d, e = ary
p d # => 4
p e # => nil

Он также имеет ограниченную форму структурирования привязки:

 a = 1, 2, 3
 p a # => [1, 2, 3]

Вы можете комбинировать эти две формы следующим образом:

a, b = b, a # Nice way to swap two variables

a, b = 1, 2, 3
p b # => 2

def foo; return 1, 2 end
a, b = foo
p a # => 1
p b # => 2

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

Вот только закуска:

def foo(((a, b, c, d), e, *f), g, *h)
  local_variables.sort.each do |lvar| puts "#{lvar} => #{eval(lvar).inspect}" end
end

foo([[1, 2, 3], 4, 5, 6], 7, 8, 9)
# a => 1
# b => 2
# c => 3
# d => nil
# e => 4
# f => [5, 6]
# g => 7
# h => [8, 9]
Йорг В. Миттаг
источник
16

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

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

Брайан Агнью
источник
4
больше свободы, больше ответственности. Опытный рубист воспользуется этим и напишет несколько красивых кодов. а рубиновые новички могут усугубить ситуацию.
fengd 05
1
Ясно, что это не всегда так, иначе ничего подобного chunkне существовало бы. Впрочем, отличный принцип. Код действительно пахнет. Раскачать.
Darth Egregious
6

Вы также можете добиться этого, возвращая массив, например

def sumdiff(x, y)
    [x+y, x-y]
end

который кажется функционально эквивалентным

def sumdiff(x, y)
    return x+y, x-y
end
Зак Сюй
источник