메서드(Methods): 프로그램의 기능을 정의하는 문법
메서드(Methods): 프로그램의 기능을 정의하는 문법
메서드는 프로그램이 실제로 하는 일을 구현해요. Ruby의 메서드 정의는 def 키워드부터 시작해요. 이번에는 메서드 이름을 짓는 법, 반환 값, 그리고 다양한 인자 문법을 하나씩 짚어볼게요. 이 문서는 메서드 정의에만 집중하고, 호출하는 쪽 문법은 별도 문서에서 다룰게요.
출처: 공식문서 - Methods
본문
간단한 메서드 정의부터 볼게요.
def one_plus_one
1 + 1
end
메서드 정의는 def 키워드, 메서드 이름, 메서드 본문, end 키워드로 이루어져요. 호출하면 메서드 본문이 실행되고, 이 메서드는 2를 반환해요. Ruby 3.0부터는 표현식이 정확히 하나뿐인 메서드를 위한 축약 문법도 있어요.
def one_plus_one = 1 + 1
메서드 이름
메서드 이름은 연산자 중 하나이거나, 문자나 8번째 비트가 설정된 문자로 시작해야 해요. 그 뒤에는 문자, 숫자, _(밑줄), 또는 8번째 비트가 설정된 문자가 올 수 있어요. 관례적으로 여러 단어로 된 메서드 이름은 밑줄로 단어를 구분해요.
단항 연산자 메서드 -와 +를 정의할 때는 연산자 뒤에 @를 붙여요. 이 @는 단항 연산자를 이항 연산자와 구분하기 위해 필요해요.
class C
def -@
puts "you inverted this object"
end
end
obj = C.new
-obj # prints "you inverted this object"
요소 참조와 할당 메서드 []와 []=도 정의할 수 있어요. 둘 다 인자를 하나 이상 받을 수 있고, 요소 참조([])는 인자를 안 받을 수도 있어요.
class C
def [](a, b)
puts a + b
end
def []=(a, b, c)
puts a * b + c
end
end
obj = C.new
obj[2, 3] # prints "5"
obj[2, 3] = 4 # prints "10"
반환 값
기본적으로 메서드는 본문에서 마지막으로 평가된 표현식을 반환해요. 위 예시에서 마지막(그리고 유일한) 표현식은 1 + 1이었어요. return 키워드를 쓰면 메서드가 값을 반환한다는 걸 명시적으로 드러낼 수 있어요.
def one_plus_one
return 1 + 1
end
return은 마지막 표현식이 평가되기 전에 메서드를 일찍 끝낼 때도 써요.
def two_plus_two
return 2 + 2
1 + 1 # this expression is never evaluated
end
할당 메서드의 경우, = 할당 문법을 쓸 때는 반환 값이 무시돼요. 대신 인자가 반환돼요.
def a=(value)
return 1 + value
end
p(self.a = 5) # prints 5
메서드를 직접 호출하면 실제 반환 값을 돌려받아요.
p(send(:a=, 5)) # prints 6
스코프
메서드를 정의하는 기본 문법은 클래스에 메서드를 추가해요. class 키워드로 특정 클래스에 인스턴스 메서드를 정의할 수도 있어요.
class C
def my_method
# ...
end
end
단일 객체에만 메서드를 추가할 수도 있어요. def greeting.broaden처럼 객체를 지정해서 정의하는 메서드는 싱글턴 메서드(singleton method) 라고 불러요.
def String.hello
"Hello, world!"
end
조금 더 확실한 예로, 아래처럼 특정 문자열 인스턴스에만 메서드를 붙일 수도 있어요. broaden은 greeting 문자열 인스턴스에만 존재하고, 다른 문자열에는 없어요.
greeting = "Hello"
def greeting.broaden
self + ", world!"
end
greeting.broaden # returns "Hello, world!"
인자
메서드는 인자를 받을 수 있어요. 인자 목록은 메서드 이름 뒤에 와요.
def add_one(value)
value + 1
end
인자는 메서드 본문 안의 지역 변수예요. 호출 쪽에서 add_one에 1을 주면 이 메서드는 2를 반환해요. 인자 주변의 괄호는 선택 사항이에요.
def add_one value
value + 1
end
축약 메서드 정의에서는 괄호가 필수예요.
# OK
def add_one(value) = value + 1
# SyntaxError
def add_one value = value + 1
여러 인자는 쉼표로 구분해요.
def add_values(a, b)
a + b
end
기본 값
인자에는 기본 값을 줄 수 있어요.
def add_values(a, b = 1)
a + b
end
기본 값이 있는 인자가 반드시 처음에 올 필요는 없지만, 기본 값이 있는 인자들은 함께 모여 있어야 해요. 아래는 괜찮아요.
def add_values(a = 1, b = 2, c)
a + b + c
end
아래는 SyntaxError가 나요.
def add_values(a = 1, b, c = 1)
a + b + c
end
기본 값은 이미 평가된 인자를 지역 변수로 참조할 수 있고, 인자 값은 항상 왼쪽에서 오른쪽으로 평가돼요.
def add_values(a = 1, b = a)
a + b
end
add_values
# => 2
Array 분해(Decomposition)
인자에 추가 괄호를 쓰면 Array를 분해(언팩)할 수 있어요.
def my_method((a, b))
p a: a, b: b
end
my_method([1, 2])
이 코드는 아래처럼 출력해요.
{:a => 1, :b => 2}
Array에 쓰지 않는 요소가 더 있으면 무시돼요. 분해는 얼마든지 중첩할 수 있어요.
def my_method(((a, b), c))
# ...
end
배열/해시 인자
인자 앞에 *를 붙이면 남는 인자가 모두 Array로 변환돼요.
def gather_arguments(*arguments)
p arguments
end
gather_arguments 1, 2, 3 # prints [1, 2, 3]
배열 인자는 키워드 인자보다 먼저 와야 해요.
키워드 인자
키워드 인자는 기본 값이 있는 위치 인자와 비슷해요.
def add_values(first: 1, second: 2)
first + second
end
**를 쓰면 임의의 키워드 인자를 받을 수 있어요.
def gather_arguments(first: nil, **rest)
p first, rest
end
gather_arguments first: 1, second: 2, third: 3
# prints 1 then {:second=>2, :third=>3}
**nil은 메서드가 키워드를 받는다고 표시하면서 실제로는 키워드를 받지 않는다는 뜻이에요.
def no_keywords(**nil)
end
블록 인자
블록 인자는 &로 표시하고 반드시 마지막에 와야 해요.
def my_method(&my_block)
my_block.call(self)
end
블록 인자는 블록을 다른 메서드로 전달할 때 가장 자주 써요.
def each_item(&block)
@items.each(&block)
end
인자 전달(Argument Forwarding)
... 문법으로 인자를 그대로 다른 메서드에 전달할 수 있어요.
def concrete_method(*positional_args, **keyword_args, &block)
[positional_args, keyword_args, block]
end
def forwarding_method(...)
concrete_method(...)
end
forwarding_method(1, b: 2) { puts 3 }
#=> [[1], {:b=>2}, #<Proc:...skip...>]
...로 호출하는 방법은 ...로 정의된 메서드에서만 사용할 수 있어요.
def regular_method(arg, **kwarg)
concrete_method(...) # Syntax error
end