개체가 변경 가능하다는 것은 무엇을 의미합니까?
"가변성 "는 객체의 내부 상태가 변경될 수 있음을 의미합니다. 이것은 고정된 개체를 제외한 모든 개체의 기본값입니다. , 또는 특수 개체 목록의 일부인 개체입니다.
즉, Ruby의 모든 객체가 변경 가능한 것은 아닙니다!
예를 들어 :
숫자나 기호, 심지어 true
에도 의미가 없습니다. 또는 false
(또한 객체이기도 함) 변경할 수 있습니다.
숫자 1은 항상 1이 됩니다.
그러나 다른 개체, 특히 Array 또는 Hash 개체와 같이 데이터를 저장하는 개체는 성능상의 이유로 변경할 수 있는 기능이 있어야 합니다.
대안은 무엇입니까?
새 사본을 만들 수 있습니다. 변경 사항이 있는 개체를 변경한 다음 원래 개체를 그대로 두고 이 새 개체를 반환합니다.
배열이 불변인 경우 배열의 한 요소만 변경하려면 변경되지 않은 요소를 포함하여 모든 데이터를 복사해야 합니다.
아무리 작은 것이라도 변경해야 할 때마다 100만(또는 그 이상) 요소 배열을 복사해야 한다고 상상해보세요! 그다지 효율적이지 않습니다...
어쨌든.
Ruby에서 가변성이 어떻게 작동하는지 조금 더 자세히 살펴보겠습니다.
포인터로서의 가변성과 변수
다음 두 가지 조합으로 인해 발생하는 프로그래밍 오류 범주가 있습니다.
- 변경 가능한 개체.
- 변수에는 데이터가 직접 포함되지 않고 이 데이터가 저장되는 위치에 대한 참조가 포함된다는 사실
이러한 오류가 표시되는 한 가지 방법은 변수에 '별칭'을 지정하려고 할 때입니다.
예시입니다 :
name = "Peter" other_name = name puts other_name # "Peter"
이 예에서 name
및 other_name
동일한 문자열 개체에 대한 참조를 포함합니다. 이 문자열의 내용을 표시하거나 수정하는 데 사용할 수 있습니다.
other_name
을(를) 처리하면 문제가 나타납니다. 문자열의 복사본과 같습니다.
other_name[0] = 'T' name # "Teter" other_name # "Teter"
두 변수가 동일한 문자열을 가리키기 때문에 "Peter"를 "Teter"로 변경했습니다. "Peter"를 주변에 두려고 했기 때문에 문제가 되는 것입니다.
개체 복제
이 문제를 처리하는 한 가지 방법은 dup
을 사용하는 것입니다. 방법.
이것은 Ruby에게 객체의 사본을 제공하도록 지시할 것입니다. clone
도 있습니다. 이 메서드는 개체 복사본을 제공할 뿐만 아니라 개체에 정의된 고정 상태 및 단일 메서드를 복사합니다.
예시를 보자 :
numbers = [1, 2, 3] more_numbers = numbers.dup more_numbers << 4 numbers # [1, 2, 3] more_numbers # [1, 2, 3, 4]
이 예에서 원본 numbers
가 어떻게 배열은 변경되지 않았습니다. 해당 dup
을 제거해 보세요. 세 번째 라인에 전화해서 무슨 일이 일어나는지 보세요 🙂
루비 동결 방법
개체를 원치 않는 변경으로부터 안전하게 유지하는 또 다른 방법은 개체를 '고정'하는 것입니다. 모든 Ruby 객체는 freeze
를 사용하여 고정할 수 있습니다. 방법.
개체가 고정되면 이 개체를 변경하려고 하면 RuntimeError
가 발생합니다. 예외.
참고:frozen?
을 사용할 수 있습니다. 개체가 고정되었는지 여부를 확인하는 메서드입니다.
예 :
animals = %w( cat dog tiger ) animals.freeze animals << 'monkey' # RuntimeError: can't modify frozen Array
한 가지 명심해야 할 점은 이 예제에서는 하나의 객체만 고정된다는 것입니다. 이 예제에서는 배열 자체에서 항목을 추가하거나 제거할 수 없습니다. 그러나 배열 내부의 문자열은 고정되지 않으므로 계속 변경할 수 있습니다. !
animals[1][0] = 't' # => ["cat", "tog", "tiger"]
문자열을 고정하려면 freeze
를 호출해야 합니다. 그들에. 다음과 같이:animals.each(&:freeze)
.
고정 문자열
변경 가능한 객체는 성능, 특히 문자열에도 영향을 미칩니다. 그 이유는 큰 프로그램에서 동일한 문자열이 여러 번 사용될 가능성이 높기 때문입니다.
Ruby는 두 문자열이 동일하게 보이거나 다시 말해 동일한 '내용'이 있더라도 모든 문자열에 대해 새 객체를 생성합니다. irb
에서 이런 일이 일어나는 것을 쉽게 볼 수 있습니다. object_id
를 사용하는 경우 방법.
예시입니다 :
a = 'test' b = 'test' a.object_id # 76325640 b.object_id # 76317550
이러한 개체가 추가 메모리와 추가 CPU 주기를 소비하기 때문에 문제가 됩니다.
Ruby 2.1부터 고정 문자열을 사용할 때 , Ruby는 동일한 문자열 객체를 사용합니다. 이렇게 하면 동일한 문자열의 새 복사본을 만들 필요가 없습니다. 그 결과 메모리가 약간 절약되고 성능이 약간 향상됩니다.
Rails는 광범위함을 만듭니다. 이러한 이유로 고정 문자열을 사용합니다. 예를 들어, 이 PR을 살펴보십시오.
이로 인해 Ruby 개발 팀은 문자열을 불변으로 이동하는 것을 고려하기 시작했습니다. 기본적으로 개체. 사실, 며칠 전에 출시된 Ruby 2.3에는 프로젝트에서 이를 활성화하는 두 가지 방법이 포함되어 있습니다.
하나는 # frozen_string_literal: true
를 포함하는 것입니다. 문자열을 변경할 수 없도록 하려는 모든 파일의 맨 위에 있습니다. 다른 하나는 명령줄 인수 --enable=frozen-string-literal
를 사용하는 것입니다. .
기본적으로 변경할 수 없는 문자열은 Ruby 3.0에 포함될 것입니다.
이제 미쳐서 앱의 모든 문자열을 고정하지 마십시오. 일종의 이점을 보기 위해 수백 번 사용되는 문자열에 대해서만 이 작업을 수행하려고 합니다. . 하지만 다음은 잠재적인 문자열을 고정하는 데 사용할 수 있는 도구입니다.
방법 알기
변경 가능한 객체의 모든 메소드가 실제로 객체를 변경하는 것은 아닙니다. 예를 들어, gsub 메소드는 원본을 건드리지 않고 새 문자열을 반환합니다.
이러한 방법 중 일부에는 대체 버전이 있습니다. 이는 원래 개체를 제자리에서 변경하므로 종종 더 효율적입니다. 이러한 메서드는 종종 느낌표 !
로 끝납니다. 효과를 나타냅니다.
이러한 'bang' 메서드의 두 가지 예는 gsub!
입니다. 및 map!
.
참고 :
!
로 끝나는 메소드 항상 '객체를 변경하는 메서드'를 의미하지는 않습니다.
보다 일반적인 용어로 !
기호는 '위험'을 나타내는 데 사용됩니다. 하나의 예 이것은 exit!
입니다. 이 메서드는 종료 처리기를 무시하고 프로그램을 즉시 종료합니다.
객체를 변경하고 !
로 끝나지 않는 메소드도 있습니다. 상징. 예:delete
, clear
, push
, concat
등이 있습니다.
마무리
가변성은 까다로운 주제일 수 있지만 이 게시물을 읽은 이후로 이제 이를 다룰 준비가 훨씬 더 잘 된 것입니다. 메서드가 무엇을 하는지 잘 모르는 경우 Ruby 문서를 확인하세요. 문제를 방지하는 데 도움이 됩니다.
이 기사가 유익한 정보가 되었기를 바랍니다. 공유하세요. 친구들과 함께 즐길 수 그것도. 또한 아래 뉴스레터에 가입하여 이와 같은 콘텐츠가 나올 때 더 이상 놓치지 않도록 하세요!