[ruby] Ruby에서 문자열을 만들 때 삽 연산자 (<<)가 더하기 같음 (+ =)보다 선호되는 이유는 무엇입니까?

Ruby Koans를 통해 작업하고 있습니다.

about_strings.rbtest_the_shovel_operator_modifies_the_original_stringKoan 에는 다음 주석이 포함되어 있습니다.

루비 프로그래머는 문자열을 만들 때 더하기 같음 연산자 (+ =)보다 삽 연산자 (<<)를 선호하는 경향이 있습니다. 왜?

내 생각 엔 속도와 관련이 있지만 삽 운영자가 더 빨라지게 만드는 후드 아래의 행동을 이해하지 못합니다.

누군가가이 기본 설정의 세부 사항을 설명해 주시겠습니까?



답변

증명:

a = 'foo'
a.object_id #=> 2154889340
a << 'bar'
a.object_id #=> 2154889340
a += 'quux'
a.object_id #=> 2154742560

따라서 <<새 문자열을 만드는 대신 원래 문자열을 변경합니다. 그 이유는 루비 에서 할당 인 ( 다른 연산자 에도 동일하게 적용되는 a += b) 구문상의 속기 이기 때문입니다 . 반면에 수신자를 제자리에서 변경 하는 별칭입니다 .a = a + b<op>=<<concat()


답변

성능 증명 :

#!/usr/bin/env ruby

require 'benchmark'

Benchmark.bmbm do |x|
  x.report('+= :') do
    s = ""
    10000.times { s += "something " }
  end
  x.report('<< :') do
    s = ""
    10000.times { s << "something " }
  end
end

# Rehearsal ----------------------------------------
# += :   0.450000   0.010000   0.460000 (  0.465936)
# << :   0.010000   0.000000   0.010000 (  0.009451)
# ------------------------------- total: 0.470000sec
# 
#            user     system      total        real
# += :   0.270000   0.010000   0.280000 (  0.277945)
# << :   0.000000   0.000000   0.000000 (  0.003043)


답변

Ruby를 첫 프로그래밍 언어로 배우고있는 한 친구가 Ruby Koans 시리즈의 Strings in Ruby를 살펴보면서 동일한 질문을했습니다. 나는 다음 비유를 사용하여 그에게 설명했다.

반쯤 가득 찬 물 한 잔이 있고 잔을 다시 채워야합니다.

첫 번째 방법은 새 잔을 가져다가 수도꼭지에서 물로 반쯤 채운 다음이 반쯤 가득 찬 잔으로 음료수 잔을 다시 채우는 것입니다. 잔을 리필해야 할 때마다이 작업을 수행합니다.

두 번째 방법은 반쯤 가득 찬 유리 잔을 가져다가 수도꼭지에서 바로 물로 채우는 것입니다.

하루가 끝나면 잔을 다시 채울 때마다 새 잔을 선택하면 청소할 잔이 더 많아집니다.

삽 연산자와 더하기 같음 연산자에도 동일하게 적용됩니다. 게다가 동등한 작업자는 유리를 다시 채울 필요가있을 때마다 새로운 ‘유리’를 선택하는 반면 삽 작업자는 동일한 유리를 가져다가 다시 채 웁니다. 하루가 끝나면 Plus equal 연산자를위한 더 많은 ‘유리’컬렉션.


답변

이것은 오래된 질문이지만 방금 만났고 기존 답변에 완전히 만족하지 않습니다. 삽 <<이 연결 + =보다 빠르다는 점에 대해 많은 좋은 점이 있지만 의미 론적 고려도 있습니다.

@noodl의 대답은 <<가 기존 개체를 수정하는 반면 + =는 새 개체를 만듭니다. 따라서 문자열에 대한 모든 참조가 새 값을 반영하도록 할 것인지 아니면 기존 참조를 그대로두고 로컬에서 사용할 새 문자열 값을 만들 것인지 고려해야합니다. 업데이트 된 값을 반영하기 위해 모든 참조가 필요한 경우 <<를 사용해야합니다. 다른 참조를 그대로 두려면 + =를 사용해야합니다.

매우 일반적인 경우는 문자열에 대한 참조가 하나뿐입니다. 이 경우 의미 적 차이는 중요하지 않으며 속도 때문에 <<를 선호하는 것이 당연합니다.


답변

더 빠르기 때문에 / 문자열의 복사본을 만들지 않기 때문에 <-> 가비지 수집기를 실행할 필요가 없습니다.


답변

답변 커버의 대부분 동안 +=이 새 복사본을 만들기 때문에 느린, 그 마음을 유지하는 것이 중요 +=하고 << 없는 상호 교환! 서로 다른 경우에 각각을 사용하려고합니다.

를 사용 <<하면을 가리키는 모든 변수도 변경됩니다 b. 여기서 우리는 a원하지 않을 때도 돌연변이를 일으 킵니다 .

2.3.1 :001 > a = "hello"
 => "hello"
2.3.1 :002 > b = a
 => "hello"
2.3.1 :003 > b << " world"
 => "hello world"
2.3.1 :004 > a
 => "hello world"

때문에 +=새 복사본을 만들어, 그것은 또한 변경이 가리키는 된 모든 변수를 떠난다.

2.3.1 :001 > a = "hello"
 => "hello"
2.3.1 :002 > b = a
 => "hello"
2.3.1 :003 > b += " world"
 => "hello world"
2.3.1 :004 > a
 => "hello"

이 구별을 이해하면 루프를 다룰 때 많은 두통을 줄일 수 있습니다!


답변

귀하의 질문에 대한 직접적인 대답은 아니지만 The Fully Upturned Bin은 항상 제가 좋아하는 Ruby 기사 중 하나였습니다. 또한 가비지 수집과 관련된 문자열에 대한 정보도 포함합니다.