Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

Ruby의 dup과 clone 메서드, 무엇이 다를까? 핵심 차이점 완벽 정리

Ruby에서 객체를 복사할 수 있다는 사실을 알고 계셨나요? 게다가 복사 방법도 한 가지가 아니라 두 가지나 됩니다!

바로 이 두 메서드입니다:

  • dup
  • clone

곧 두 메서드의 차이점을 자세히 살펴보겠습니다. 그 전에 먼저 이런 질문부터 드려볼까요?

객체를 복제해야 하는 이유는?

Ruby의 많은 객체는 변경 가능(mutable)합니다. 즉, 언제든 내용을 수정할 수 있죠.

그래서 객체를 변경하면서도 원본은 그대로 보존하고 싶을 때 객체를 복제하면 유용합니다.

예시를 들어볼게요. 배열의 첫 번째 요소만 제외한 나머지 요소들로 구성된 새로운 배열이 필요하다고 가정해봅시다.

첫 번째 방법은 범위 연산자를 활용하는 것입니다:

a = [1,2,3,4,5]

a[1..-1]
# [2,3,4,5]

두 번째 방법은 배열을 복제한 후 요소를 제거하는 것입니다:

b = a.clone

b.shift
# [1]

b
# [2,3,4,5]

두 예제 모두 원본 배열 a는 그대로 유지된다는 점이 공통점입니다.

Frozen(동결) 객체와의 관계

dupclone은 Ruby의 다른 메서드 쌍(map/collect처럼 서로 별칭 관계인 메서드)과 달리, 서로 미묘하지만 중요한 차이점을 가지고 있습니다.

두 가지 대상의 공통점과 차이점을 비교해 보는 것이해도를 높이는 아주 좋은 학습 방법입니다.

두 메서드 모두 객체를 복사한다는 점은 같지만, dup은 객체의 메타 정보(속성)까지는 복사하지 않는다는 점이 다릅니다.

여기서 말하는 객체 속성이란 다음과 같습니다:

  • frozen 상태 (동결 여부)
  • tainted 상태 (오염 여부)
  • 싱글턴 클래스(singleton class)

실제 예제를 통해 확인해 보겠습니다:

a = Object.new.freeze

b = a.dup
b.frozen?
# false

b = a.clone
b.frozen?
# true

동결된 객체를 dup으로 복사하면 동결 상태가 해제되지만, clone으로 복사하면 동결 상태가 그대로 유지됩니다.

참고로 Ruby 2.4부터는 clone에 옵션을 지정하여 원본의 동결 상태를 무시하고 복사할 수 있습니다.

예시:

a.clone(freeze: true)   # 강제로 동결 상태로 복사
a.clone(freeze: false)  # 동결 상태를 해제하며 복사

얕은 복사 vs 깊은 복사 (Shallow Copy vs Deep Copy)

객체 복사에는 겉으로 드러나지 않는 중요한 개념이 하나 더 숨어 있습니다.

dup이든 clone이든 어떤 메서드로 복사하든, 기본적으로 수행되는 것은 얕은 복사(shallow copy)라는 점입니다.

즉, 객체 내부에 포함된 다른 객체들은 함께 복사되지 않습니다.

다르게 표현하면:

문자열로 이루어진 배열을 복사할 때, 복사되는 것은 배열 자체뿐이며 배열 안의 문자열들은 복사되지 않습니다.

직접 확인해 보겠습니다:

original = %w(apple orange banana)
copy     = original.clone

original.map(&:object_id)
# [23506500, 23506488, 23506476]

copy.map(&:object_id)
# [23506500, 23506488, 23506476]

배열을 복제했음에도 object_id가 동일하게 출력됩니다. 즉, 배열 안의 문자열들은 여전히 같은 객체라는 뜻입니다.

내부 객체까지 복사하려면 다음과 같이 작성할 수 있습니다:

strings.clone.map(&:clone)

이렇게 하면 배열과 문자열 모두 복제됩니다. 다만 주의할 점은 이 방법 역시 한 단계(1 depth)만 복사한다는 것입니다. 더 깊은 계층까지 복사해야 한다면 ActiveSupport에서 제공하는 deep_dup 메서드를 활용해 보세요.

정리

지금까지 Ruby에서 객체를 복제하는 방법을 배웠습니다. dupclone 메서드의 차이점, 그리고 얕은 복사와 깊은 복사의 개념까지 살펴보았습니다.

  • dup: frozen 상태, 싱글턴 클래스 등 메타 정보를 복사하지 않음
  • clone: frozen 상태와 싱글턴 클래스까지 그대로 복사함
  • 두 메서드 모두 기본적으로 얕은 복사를 수행하므로, 중첩된 객체까지 복사하려면 추가 처리 필요

읽어주셔서 감사합니다!