2013-05-13 2 views
2

I 변수로 이루어진 어레이를 가지며, I 각각에 동일한 동작을 수행하고, 원래 변수에 결과를 저장할 :변경 값

(one, two, three) = [1, 2, 3] 

[one, two, three].map!{|e| e += 1} 
# => [2, 3, 4] 

# But: 
[one, two, three] 
# => [1, 2, 3] 

# You have to: 

(one, two, three) = [one, two, three].map{|e| e += 1} 
# => [2, 3, 4] 

[one, two, three] 
# => [2, 3, 4] 

이되지 않는다 그것을하는 "올바른 방법"처럼 보이지만, 나는 "올바른 길"을 찾아 낼 수있는 것이 아닙니다. 나는 또한 무슨 일이 벌어지고 있는지 모호한 생각을 가지고있다. 그러나 나는 그렇게 확신 할 수 없다. 그래서 설명은 인정 될 것이다.


내 실제 사용 사례 I 매개 변수의 이름 했으니 내가 e = File.new(e) if e.is_a? String

답변

4

루비의 숫자 (예 : Fixnum)는 변경할 수 없습니다. 기본 값은 변경할 수 없습니다.

one = 1을 할당하면 새로운 할당없이 one의 값을 변경할 수 없습니다. 당신이 할 때 one += 1. 실제로 새 값 2을 변수 one에 할당하고 있습니다. 그것은 완전히 새로운 대상입니다.

당신은 object_id (일명, __id__)을 보면이 더 명확하게 볼 수 있습니다

one = 1 
1.object_id  # => 2 
one.object_id # => 2 
one += 1 
one.object_id # => 5 
2.object_id  # => 5 

는 이제 Array#map! 성명에서, 실제로 one 객체를 변경하지 않는 것입니다. 이 객체에 대한 참조는 배열에 저장됩니다. 실제 변수가 아닙니다. map!으로 열거하면 블록에 의해 반환 된 개체가 같은 위치의 내부 참조 위치에 저장됩니다. 다음과 같은 map!를 통해 첫 번째 패스의 생각 :이 Fixnum 객체는 불변이기 때문에

one = 1 
one.object_id  # => 2 

arr = [one] 

arr[0].object_id # => 2 

arr[0] += 1 # You are re-setting the object at index 0 
       # not changing the original `one`'s value 

arr[0]   # => 2 
arr[0].object_id # => 5 

one    # => 1 
one.object_id  # => 2 

가 자신의 값을 변경할 수있는 방법이 없습니다.

(one, two, three) = [1, 2, 3] 
one.object_id  # => 3 
two.object_id  # => 5 
three.object_id # => 7 

(one, two, three) = [one, two, three].map{|e| e += 1} 
one.object_id  # => 5 
two.object_id  # => 7 
three.object_id # => 9 
2

이 시도 해요 :

a = [one, two, three] 
a.map!{|e| e += 1} 

문제는 [one, two, three]이를 저장하는 변수가되지 않는 것입니다 배열, 당신이 그것을 쓸 때마다 아주 새로운 배열입니다. a = [one, two, three]을 설정하면 작동 할 수있는 값을 저장하는 변수가 생깁니다.


DARSHAN이 실제로 원래의 변수 하나, 둘, 3의 값을 수정하지 않는다는 의견에서 지적, 그는 맞습니다. 하지만 할 수있는 방법이있다 :

["one", "two", "three"].each{ |e| eval "#{e} += 1" } 

그러나 그것은 꽤 추한 대신 실제 변수의 배열에 문자열을 사용에 의존하고 아마 당신은 이미 해낸 것보다 훨씬 더 나쁘다 :

(one, two, three) = [one, two, three].map{|e| e += 1} 
+0

이것은 작동하지 않습니다. '하나', '두', '세'는 변하지 않은 채로 남아 있습니다. –

+0

맞습니다, Darshan. 내 대답이 업데이트되었습니다. –

0

당신이 정말로 fixnums 참조 변수의 값을 변경하려면, 그럼 당신이하고있는 것이 있습니다 : 이것은 당신이 다시 원래 값으로 당신의 map의 결과를 참조를 해제해야 할 이유 Ruby에서 할 수있는 최선의 방법.즉, 이 아닌을 세 개의 개별 변수로 저장하는 것이 더 나을 것입니다. 오히려 one, twothree을하는 것보다, 당신은 a[2]을 통해 a[0]이 주위 a에 합격하거나, h[:three] 통해 h[:one] 주위 h를 전달할 수 있습니다. h[:some_name] 변수 이름을 사용 가까이 있기 때문에

a = [1, 2, 3] 
a.map!{|e| e += 1} 
a # => [2, 3, 4] 

h = {:one=>1, :two=>2, :three=>3} 
h.each_key{|k| h[k] += 1} 
h # => {:one=>2, :two=>3, :three=>4} 

두 번째 옵션은 해시를 사용하여, 당신이 원하는 아마 가깝다.