지난 챕터에서는 1부터 10까지 더하는 코드를 지겹게 만들었었죠. 코드의 반복을 피하기 위해 함수로 만들어봅시다.

# array를 인자로 받아 배열의 모든 원소를 더해서 리턴하는 함수 sum_all 을 만들어 봅시다.
def sumall(array)
  total = 0
  array.each {|num| total += num}
  return total
end

puts sumall(1..10)
# => 55

def 키워드로 시작해서 end 로 끝내면 됩니다. C/Java와 다른 점은 인자와 리턴값의 타입을 명시하지 않는다는 거겠죠? 타입을 명시하지는 않지만 타입 체크를 하지 않는 것은 아닙니다. 엉뚱한 타입을 넘겼을 경우 타입 에러가 돌아옵니다.

# 위 코드에서 계속됩니다.
puts sumall(35)

이 코드를 실행시키면 다음과 같은 에러를 뱉습니다.

method.rb:3:in `sum_all': undefined method `each' for 35:Fixnum (NoMethodError) from method.rb:8

인자로 넘겨준 35는 FixNum, 즉 정수 타입이기 때문에 35.each 함수를 부를 수 없다는 뜻의 에러입니다.

루비에서는 인자를 받지 않는 함수도 만들 수 있고, 인자에 기본값을 줄 수도 있으며, 인자의 개수를 바꿔가며 넣어줄 수도 있습니다.

# 1에서 45 사이의 랜덤한 정수 6개를 돌려주는 함수를 만들어봅시다.
# 인자를 받지 않는 함수의 경우 괄호는 생략해도 됩니다.
def lotto
  # rand(n)은 0..n-1 사이의 랜덤한 정수를 반환합니다.
  [rand(45)+1, rand(45)+1, rand(45)+1, rand(45)+1, rand(45)+1, rand(45)+1]
end

# p는 puts와 비슷하지만 결과값의 내용을 보여주는, 디버깅에 주로 사용되는 함수입니다.
p lotto
# => [19, 37, 13, 42, 22, 37]

위에서 선언한 함수 lotto에는 return 키워드가 없는 걸 볼 수 있습니다. 루비의 함수는 return 이 없을 경우 마지막 줄의 리턴값(지난 챕터에서 말씀드렸듯, 루비의 모든 실행문에는 리턴값이 존재합니다.)을 리턴합니다. 따라서 위와 같은 한줄짜리 함수는 return 없이도 간단히 쓸 수 있습니다.

이번에는 인자를 받지 않을때는 위 함수와 똑같이 동작하지만, 정수의 개수와 최대값을 인자로 넣어줄 수도 있는 함수를 만들어 봅시다.

def lotto(num = 6, max = 45)
  # Array.new는 새 배열을 만들어주는 함수입니다.
  # 인자 하나(num)와 블록 하나( {rand(max)+1} )를 받아서,
  # num 크기의 배열을 {rand(max)+1} 로 채워줍니다.
  Array.new(num) {rand(max)+1}
end

p lotto
# => [30, 20, 23, 32, 5, 29]
p lotto(3, 25)
# => [25, 3, 10]

임의 개수의 인자를 받으려면 인자 이름 앞에 *을 붙여줍니다. 함수 내에서는 해당하는 이름의 배열로 자동 변환됩니다.

def hello(*list)
  list.each {|name| puts "Hello, " + name + "!"}
end

hello("C", "C++", "Java")
# => Hello, C!
# => Hello, C++!
# => Hello, Java!