Zwróć dwie i więcej wartości z metody

105

Czy istnieje możliwość zwrócenia wielu wartości z metody? Coś takiego:

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

[a, b, c] = someMethod
demas
źródło

Odpowiedzi:

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
źródło
Powinieneś używać formatowania kodu, a nie formatowania tekstu. Wcięcie linii o cztery spacje i dziwność spowodowana >>zachętą irb zniknie.
Chris Lutz,
4
Ponieważ jawny zwrot jest uważany za nieidiomatyczny Ruby, możesz również użyć niejawnego zwrotu, jawnie umieszczając zwracane wartości na liście:def foo_and_bar; ['foo', 'bar']; end
Dennis
43

Ruby ma ograniczoną formę wiązania destrukturyzującego:

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

Ma również ograniczoną formę wiązania struktury:

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

Możesz połączyć te dwie formy w następujący sposób:

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

Jest kilka innych rzeczy, które możesz zrobić z destrukturyzacją / tworzeniem wiązania. Nie pokazałem, używając operatora splat ( *) po prawej stronie. Nie pokazałem zagnieżdżenia (używając parafii). Nie pokazałem, że na liście parametrów bloku lub metody można użyć wiązania destrukturyzującego.

Oto tylko przystawka:

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
źródło
16

Chociaż zwracanie wielu wartości jest często przydatne, zwykle uważam, że jest to wskaźnik do nowego wymagania dotyczącego obiektu.

Oznacza to, że zwykle stwierdzam, że te zwracane wartości są ściśle powiązane ze sobą w znaczeniu / kontekście i jako takie są przekazywane. W takich przypadkach utworzyłbym nowy obiekt, aby powiązać je ze sobą. To szczególny zapach kodu, który nauczyłem się rozpoznawać.

Brian Agnew
źródło
4
więcej wolności, więcej odpowiedzialności. Doświadczony rubista wykorzystałby to i napisałby piękne kody. podczas gdy debiutanci rubinów mogą pogorszyć sytuację.
fengd
1
chunkOczywiście nie zawsze tak jest, bo inaczej rzeczy takie jak nie istniałyby. Jednak doskonała zasada. Zapach kodu rzeczywiście. Rock on.
Darth Egregious
6

Możesz to osiągnąć również zwracając tablicę, na przykład

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

co wydaje się funkcjonalnie równoważne z

def sumdiff(x, y)
    return x+y, x-y
end
Zack Xu
źródło