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

루비 self 키워드 완벽 정리: 개념부터 실전 활용법까지

Ruby를 배우다 보면 self 키워드의 사용법이 꽤 헷갈릴 때가 있습니다.

대체 어떻게 작동하는 걸까요?

정확히 self란 무엇일까요?

self현재 객체(current object)에 접근할 수 있게 해주는 루비 키워드입니다.

만약 객체가 무엇인지 잘 모르겠다면, 객체 지향 프로그래밍과 관련된 학습 자료를 먼저 참고해 보시길 권합니다.

그런데 이 '현재 객체'는 문맥(context)에 따라 달라집니다.

문맥이라고요?

네, 문맥이란 특정 시점에 여러분의 코드가 어디에 위치해 있는지를 의미합니다.

예를 들어볼까요?

코드가 인스턴스 메서드 안에 있다면 self는 해당 클래스의 인스턴스, 즉 하나의 객체를 가리킵니다.

직접 실행해서 확인해 볼 수도 있습니다.

아래 코드를 실행해 보세요:

def coffee
  puts self
end

coffee
# main

이 코드는 self의 값을 출력하는 coffee 메서드를 정의하고 곧바로 호출합니다.

main이 출력될까요?

main은 최상위(top-level) 객체의 이름입니다. 클래스 바깥에서 정의한 모든 메서드는 이 객체에 속하게 됩니다.

방금 정의한 coffee 메서드도 마찬가지죠.

반면, Cat이라는 클래스 내부에 메서드를 정의하면 selfCat 객체가 됩니다.

다음 예제를 보세요:

class Cat
  def meow
    puts self
  end
end

Cat.new.meow
# <Cat:0x7a14c5>

이 두 예제에서 알 수 있듯이, self의 값은 어디에서 사용하느냐에 따라 달라집니다.

자, 이제:

무엇이든 그 존재 이유를 이해하면 훨씬 잘 이해할 수 있다고 생각합니다.

그렇다면 self는 왜 유용할까요?

몇 가지 예제를 통해 살펴보겠습니다.

self로 메서드와 변수 구분하기

self의 실용적인 용도 중 하나는 메서드와 지역 변수를 구별하는 것입니다.

변수와 메서드에 같은 이름을 붙이는 것은 좋은 습관이 아닙니다. 하지만 어쩔 수 없이 그런 상황에 놓였다면 self.method_name 형태로 메서드를 호출할 수 있습니다.

무슨 말인지 예제로 확인해 볼까요?

class Example
  def do_something
    banana = "variable"

    puts banana
    puts self.banana
  end

  def banana
    "method"
  end
end

Example.new.do_something

# "variable"  => puts banana
# "method"    => puts self.banana

여기에는 do_something 메서드 안에 banana라는 지역 변수가 있고, 동시에 banana라는 메서드도 존재합니다.

이때 루비는 지역 변수에 우선순위를 부여합니다.

그렇기 때문에 banana 변수의 값을 출력하는 대신 banana 메서드를 호출하려면 반드시 self를 사용해야 합니다.

다음으로:

실무에서 더 흔하게 쓰이는 사례를 살펴보겠습니다. 바로 클래스 메서드 정의입니다!

self로 클래스 메서드 정의하기

self의 가장 대표적인 용도는 단연 클래스 메서드(class-level method) 정의입니다.

한 번쯤은 보셨을 겁니다.

바로 def self.method_name 형태의 메서드 정의 말이죠.

예를 들면 다음과 같습니다:

class Salad
  def self.buy_olive_oil
    # ...
  end
end

Salad.buy_olive_oil

여기서의 self는 클래스 이름인 Salad와 동일합니다.

왜 이런 방식이 유용할까요?

메서드를 정의할 때마다 클래스 이름을 직접 쓰지 않아도 되기 때문에, 나중에 클래스 이름을 변경할 때 코드 수정이 훨씬 수월합니다.

덕분에 코드도 덜 복잡해지고 읽기 좋아집니다.

그래서 우리는 def Salad.buy_olive_oil 대신 def self.buy_olive_oil처럼 작성하는 것입니다.

self의 그 밖의 활용법

네, self의 용도는 이것보다 더 많습니다. 미리 알아두면 분명 도움이 됩니다.

예를 들면:

메서드 안에서 현재 객체와 다른 객체를 비교할 때 사용할 수 있습니다.

이런 식으로요:

def ==(other)
  self == other
end

디버깅 목적으로도 활용할 수 있습니다. 지금 다루고 있는 객체가 무엇인지 확인하고 싶을 때 유용하죠.

이렇게요:

p self

또한 반환값으로 활용하면 빌더 패턴(Builder Design Pattern) 같은 디자인 패턴을 구현할 수 있습니다.

예제:

class Salad
  def initialize
    @ingredients = []
  end

  def add_nuts
    @ingredients << :nuts

    self
  end
end

my_salad = Salad.new.add_nuts

정리하면, self의 유용한 활용법은 다음과 같습니다:

  • 클래스 메서드 정의
  • 같은 이름의 지역 변수가 있을 때 인스턴스 메서드 호출
  • self 반환 (빌더 패턴)
  • 디버깅
  • 객체 비교 (==)
  • 메서드 호출의 기본 수신자(receiver)

self vs itself

이 주제를 마무리하기 전에 한 가지 더 짚고 넘어갈 것이 있습니다.

바로 Kernel#itself 메서드입니다.

객체에 호출하면 그 객체 자신을 그대로 반환하는 메서드입니다.

예제:

[1,2,3,nil].select(&:itself)

# [1, 2 ,3]

이 예제는 배열에서 nilfalse 값을 걸러냅니다.

두 개념의 차이를 정리하면:

  • self는 키워드입니다. 값은 어디에서 사용하느냐에 따라 결정됩니다.
  • itself는 메서드입니다. 값은 어떤 객체에 사용하느냐에 따라 결정됩니다. (1.itself에서 1이 바로 그 객체죠)

도움이 되었기를 바랍니다.

마치며

지금까지 루비의 self 키워드가 정확히 무엇인지, 왜 유용한지, 그리고 어떻게 활용하는지 살펴봤습니다.

이제 직접 코드로 연습해 볼 차례입니다.

읽어주셔서 감사합니다! 🙂