Retorna dois ou mais valores de um método

105

Existe alguma possibilidade de retornar vários valores do método? Algo assim:

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

[a, b, c] = someMethod
demas
fonte

Respostas:

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
Aditya Mukherji
fonte
Você deve usar formatação de código, não formatação de texto. Recue as linhas quatro espaços e a estranheza causada pelo >>prompt do irb irá embora.
Chris Lutz
4
Já que um retorno explícito é considerado Ruby não idiomático, você também pode usar um retorno implícito colocando explicitamente os valores de retorno em uma lista:def foo_and_bar; ['foo', 'bar']; end
Dennis
43

Ruby tem uma forma limitada de ligação de desestruturação:

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

Ele também tem uma forma limitada de vinculação de estruturação:

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

Você pode combinar essas duas formas da seguinte maneira:

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

Existem várias outras coisas que você pode fazer com vinculação de desestruturação / estruturação. Eu não mostrei usando o operador splat ( *) no lado direito. Não mostrei aninhamento (usando parênteses). Não mostrei que você pode usar o bind de desestruturação na lista de parâmetros de um bloco ou método.

Aqui está apenas um aperitivo:

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]
Jörg W Mittag
fonte
16

Embora retornar vários valores geralmente seja útil, geralmente acho que é um ponteiro para um novo requisito de objeto.

Ou seja, geralmente acho que esses valores de retorno estão intimamente ligados em significado / contexto e são transmitidos como tal. Então, nesses casos, eu criaria um novo objeto para uni-los. É um cheiro de código específico que aprendi a reconhecer.

Brian Agnew
fonte
4
mais liberdade, mais responsabilidade. Rubistas experientes tirariam proveito disso e escreveriam belos códigos. enquanto novatos em rubis podem piorar as coisas.
fengd
1
Bem, claramente nem sempre é o caso, ou então coisas como chunknão existiriam. Excelente princípio. Cheiro de código, de fato. Rock on.
Darth Egregious
6

Você pode conseguir isso retornando uma matriz também, como

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

que parece funcionalmente equivalente a

def sumdiff(x, y)
    return x+y, x-y
end
Zack Xu
fonte