Ruby는 어떻게 두 개의 값을 반환합니까?


94

배열의 값을 바꿀 때마다 값 중 하나를 참조 변수에 저장했는지 확인합니다. 하지만 Ruby가 두 값을 반환하고 자동으로 두 값을 바꿀 수 있다는 것을 알았습니다. 예를 들면

array = [1, 3, 5 , 6 ,7]
array[0], array[1] = array[1] , array[0] #=> [3, 1] 

루비가 어떻게하는지 궁금합니다.


9
기술적으로 Ruby는 두 개의 값을 반환하지 않습니다. 두 개의 변수에 차례로 할당되는 하나의 배열을 반환 할 수 있습니다.
Charles Caldwell

답변:


164

다른 언어와 달리 Ruby의 모든 메소드 호출의 반환 값은 항상 객체입니다. Ruby의 모든 것과 마찬가지로 nil자체가 객체 이기 때문에 가능 합니다.

당신이 보게 될 세 가지 기본 패턴이 있습니다. 특정 값을 반환하지 않음 :

def nothing
end

nothing
# => nil

특이 값 반환 :

def single
  1
end

x = single
# => 1

이것은 다른 프로그래밍 언어에서 기대하는 것과 일치합니다.

여러 반환 값을 처리 할 때 상황이 약간 다릅니다. 다음과 같이 명시 적으로 지정해야합니다.

def multiple
  return 1, 2
end

x = multiple
# => [ 1, 2 ]
x
# => [ 1, 2 ]

여러 값을 반환하는 호출을 만들 때 값을 독립 변수로 나눌 수 있습니다.

x, y = multiple
# => [ 1, 2 ]
x
# => 1
y
# => 2

이 전략은 다음과 같은 대체 유형에도 적용됩니다.

a, b = 1, 2
# => [1, 2]
a, b = b, a
# => [2, 1]
a
# => 2
b
# => 1

8
명시 적으로 배열을 반환하면 [1, 2]위의 예제와 동일하게 작동합니다.
Hauleth

6
@hauleth 좋은 관찰입니다. 나는 1,2그 자체로 유효하지 않지만 return 1,2또는 [1,2]작동 중이 라는 것을 분명히해야 했다 .
tadman

50

아니요, Ruby는 실제로 두 개체 반환을 지원하지 않습니다. (BTW : 변수가 아닌 개체를 반환합니다.보다 정확하게는 개체에 대한 포인터를 반환합니다.)

그러나 병렬 할당을 지원합니다. 할당의 오른쪽에 둘 이상의 객체가있는 경우 객체는 다음으로 수집됩니다 Array.

foo = 1, 2, 3
# is the same as
foo = [1, 2, 3]

할당의 왼쪽에 "대상"(변수 또는 setter 메서드)이 두 개 이상있는 경우 변수 Array는 오른쪽의 요소에 바인딩됩니다 .

a, b, c = ary
# is the same as
a = ary[0]
b = ary[1]
c = ary[2]

오른쪽이 하지Array , 상기 한 사용으로 변환한다 to_ary방법

a, b, c = not_an_ary
# is the same as
ary = not_an_ary.to_ary
a = ary[0]
b = ary[1]
c = ary[2]

두 가지를 합치면

a, b, c = d, e, f
# is the same as
ary = [d, e, f]
a = ary[0]
b = ary[1]
c = ary[2]

이와 관련된 것은 할당의 왼쪽에있는 표시 연산자입니다. 그것은 "takeArray 오른쪽에있는 의 모든 남은 요소를 가져옵니다 "를 의미합니다.

a, b, *c = ary
# is the same as
a = ary[0]
b = ary[1]
c = ary.drop(2) # i.e. the rest of the Array

마지막으로 괄호를 사용하여 병렬 할당을 중첩 할 수 있습니다.

a, (b, c), d = ary
# is the same as
a = ary[0]
b, c = ary[1]
d = ary[2]
# which is the same as
a = ary[0]
b = ary[1][0]
c = ary[1][1]
d = ary[2]

때를 return하는 방법이나next 또는 break블록에서, 루비 때문에, 할당의 오른쪽과 같은이-의 종류를 취급합니다

return 1, 2
next 1, 2
break 1, 2
# is the same as
return [1, 2]
next [1, 2]
break [1, 2]

그건 그렇고, 이것은 메서드와 블록의 매개 변수 목록에서도 작동합니다 (메소드가 더 엄격하고 블록이 덜 엄격함).

def foo(a, (b, c), d) p a, b, c, d end

bar {|a, (b, c), d| p a, b, c, d }

예를 들어 "덜 엄격"한 블록은 Hash#each작동합니다. 그것은 실제로 yieldSA 단일 두 요소Array 블록에 키와 값의,하지만 우리는 일반적으로 쓰기

some_hash.each {|k, v| }

대신에

some_hash.each {|(k, v)| }

16

tadman과 Jörg W Mittag는 나보다 Ruby를 더 잘 알고 있으며, 그들의 대답은 틀리지 않지만 OP가 알고 싶어하는 것에 대답하고 있다고 생각하지 않습니다. 그래도 질문이 명확하지 않다고 생각합니다. 내 이해에서 OP가 요청하려는 것은 여러 값을 반환하는 것과 관련이 없습니다.


진짜 질문은 두 변수의 값 ab(또는 원래 질문에서와 같이 배열의 두 위치) 전환하려는 경우 왜 시간 변수를 사용할 필요가 없다는 것입니다.temp 다음과 같은 것입니다.

a, b = :foo, :bar
temp = a
a = b
b = temp

그러나 다음과 같이 직접 수행 할 수 있습니다.

a, b = :foo, :bar
a, b = b, a

대답은 다중 할당에서 전체 왼쪽을 할당하기 전에 전체 오른쪽이 평가되고 하나씩 수행되지 않는다는 것입니다. 그래서a, b = b, aa = b; b = a.

양측 =의 용어 수가 서로 다른 경우 조정에서 뒤 따르는 할당 전에 전체 오른쪽을 먼저 평가하는 것이 필요 하며 Jörg W Mittag의 설명이 간접적으로 관련 될 수 있지만 이것이 주요 문제는 아닙니다.


8

값이 적은 경우 배열이 좋은 옵션입니다. 결과 순서를 알 필요없이 (그리고 혼동 할 필요없이) 여러 반환 값을 원할 경우, 원하는 이름이 지정된 값을 포함하는 해시를 반환하는 방법이 있습니다.

예 :

def make_hash
  x = 1
  y = 2
  {x: x, y: y}
end

hash = make_hash
# => {:x=>1, :y=>2}
hash[:x]
# => 1
hash[:y]
# => 2
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.