Follow Me: I Meet Ruby 2
간만에 다시 Ruby 입니다 ^^
이번엔 함수와 클래스에 대해서 알아보겠습니다.


함수 정의 및 사용 방법


함수는 키워드 def 로 시작해서 end로 끝이 납니다.
def 함수이름 (인자 목록)
함수 내용
end
이런 구조가 됩니다. 그리고 함수의 return 값을 얻기 위해서는 return 키워드를 사용하면 됩니다. 그렇지 않으면 마지막에 사용된 expression 이 반환됩니다. Ruby는 statement 가 없고 모두 expression 이기 때문에 보통 return 하고 싶은 값을 함수의 마지막에 계산하거나 적어주기만 하면 됩니다.

def addTen( aNumber )
  aNumber + 10
end

이렇게 정의해주고, 아래처럼 호출해주면

print addTen( 20 )

화면에 30이 찍히게 되는거죠. C계열 언어에서와의 눈에 띄는 차이점은
1. 함수의 시작은 키워드 def로 한다
2. return 은 명시적으로 적어줘도 되지만 적지 않으면 마지막 expression 이 실행된다.
3. 인자 값의 타입은 필요없다.
4. 반환 값의 타입을 적어줄 필요가 없다.
또 한가지, 함수의 인자를 명시하기 위한 괄호는 생략 가능합니다. print addTen 20 도 같은 결과를 보여줍니다. 하지만, 한 눈에 관계를 알아보기 힘든 경우에는 괄호를 사용하는 쪽이 좋습니다.


클래스 정의 및 사용방법


Ruby는 객체지향 스크립트 언어라고 했습니다. 객체지향 언어에는 빠지지 않는 개념이 있는데, 바로 클래스입니다. Ruby에서도 클래스를 지원합니다. 또한 객체지향을 이루는 여러 개념들을 훌륭하게 지원해줍니다.

class의 시작은 키워드 class로 시작합니다. 그리고 함수와 마찬가지로 end로 끝나네요. 이번엔 샘플부터 보고 시작하도록 하겠습니다.

class Jedi
def initialize(name)
  @name = name
end

def use_force()
  puts "#{@name} uses force"
end

attr_reader :name
end

대충 봐도 세 개의 함수를 가진 Jedi 라는 클래스가 있다는 걸 알 수 있습니다. force를 사용할 줄 아는 제다이를 표시하기 위한 클래스 입니다 ^^
initialize 함수부터 볼까요? 주의깊게 살펴보면 이 함수는 @name 이라는 변수를 가지고 있다는 것을 알 수 있습니다. 이 변수에다가 인자로 받은 name 을 저장하는군요. 여기서 잠시 Ruby의 변수관련 네이밍Naming을 보겠습니다.
  • 지역 변수: 알파벳 소문자로 시작. 초기화 해서 사용해야 한다.
  • 전역 변수: $로 시작. 초기화 시키지 않으면 nil
  • 임시(인스턴스) 변수: @로 시작. 초기화 시키지 않으면 nil
  • 클래스 변수: @@로 시작. 초기화 시키지 않으면 nil
  • 클래스 정수: 알파벳 대문자로 시작. 초기화 시키지 않으면 nil
인스턴스 변수가 @로 시작하는 것을 알 수 있습니다. 클래스에서 사용되는 변수니까 @@가 아니냐는 생각이 드십니까? Ruby의 클래스 변수라는 것은 다른 객체지향 언어에서 static 이라는 키워드를 사용한 것과 같다고 생각해주시면 됩니다.
이제 @name이 인스턴스 변수라는 것을 알았습니다. 그 밖의 변수는 아직 사용하지 않는군요. 그런데 @name의 값은 클래스가 생성될 때 설정되는 것이 좋지 않을까요? 새로 임명된 제다이가 이름이 없다면 얼마나 난감하겠습니까! 그래서 initialize 라는 함수 안에 넣어둔 것입니다. initialize 함수는 생성자Constructor를 의미합니다. 다른 OOPL 처럼 오버로딩해서 사용할 수 있습니다.
실제 사용은 다음과 같겠죠.

obiwan = Jedi.new("Obi-wan")
obiwan.use_force()

Java나 C#같은 발전된 형태의 OOPL을 보면 getter, setter에 대한 개념이 나옵니다. 멤버변수에 대한 접근을 제한하면서 안전하고 효과적으로 사용하기 위한 개념인데, 개인적으로 C#에서의 Property 형태를 선호합니다. 우리의 사랑스런 Ruby에게는 accessor가 있습니다. attr_reader 혹은 attr_writer 라는 키워드를 사용하며, 인스턴스 변수에 읽기전용 혹은 쓰기전용 속성을 부여하는데 주로 사용됩니다. Jedi 클래스의 경우

attr_reader :name

name 인스턴스 변수에 대한 접근제한을 읽기 전용으로 했으므로 puts yoda.name 는 할 수 있지만 yoda.name = "Padme" 는 할 수 없는 것이죠. 자세히 보면 @name 이 :name으로 바뀐 것을 알 수 있는데, 이에 대해서는 다음에 설명하도록 하겠습니다. 만약 읽기, 쓰기 모든 속성을 주고 싶다면 attr_accessor 키워드를 사용하면 됩니다.

혹은 attr_xxx 키워드를 사용하지 않고
def name
  @name
end
def name=(str) # name의 뒤에 공백이 있으면 안됩니다
  @name = str
end
이런 식으로 만들어 줄 수도 있겠습니다. 무척 유연하죠? 리소스의 Late binding을 지원하기 위해서 위의 방법을 응용할 수 있겠습니다.

클래스의 주된 특징 중 하나인 상속에 대해 알아보겠습니다. 루비는 C++과는 달리 하지만 Java와 C# 처럼 다중 상속을 지원하지 않습니다. (하지만, Mixin 이라는 것으로 다중상속과 같은 행위를 할 수 있습니다. 이에 대해서는 다음에 다루도록 하겠습니다)

class JediMaster < Jedi
def initialize(name, in_jedi_council)
  supur(name)
  @in_jedi_council = in_jedi_council
end

attr_accessor :in_jedi_council
end

상속을 하는 간한한 예제입니다. 제다이는 수련과정을 거쳐서 제다이 마스터가 됩니다. 마찬가지로 생성자가 있는데, 생성자 initialize 안에 보면 super 라는 함수를 호출하는 것을 알 수 있습니다. Java 사용자라면 익숙하겠죠? C#의 base와 같은 이 함수는 자신의 부모의 생성자를 호출하는 함수입니다. 그러니까 JediMaster를 호출할 때 넘긴 name 인자는 부모인 Jedi 클래스가 받아서 @name을 초기화 시켜줍니다. 추가로 제다이 마스터는 제다이 위원회의 멤버가 될 수 있는데, 처음에 마스터가 되었을 때는 멤버가 아니더라도 나중에 가입이 될 수 있을테니 @in_jedi_council는 attr_accessor 로 주었습니다.

yoda = JediMaster.new("Yoda", true)
yoda.in_jedi_council = true

super를 알았으니 자기 자신을 접근하는 방법도 알아봅시다. 클래스 내부에서 self 를 사용하면 다른 언어들의 this 와 같은 역할을 해줍니다. 추가적으로 self는 static method를 정의하기 위해서도 사용됩니다. 흔히 사용되는 Math 클래스를 생각해보면, sin, cos, tan 같은 함수들은 인스턴스의 함수가 아니라 클래스의 함수가 됩니다. 즉, Math.sin(), Math.cos() 이렇게 호출하기 위해서는

class Math
...
def self.sin()
  ...
end
end

이런 식으로 정의를 하면 되겠습니다.

재미있는 Ruby FAQ: "Ruby" 스크립트를 컴파일 할 수 있습니까?
  시험적으로 작성된 x86용 Just In Time 컴파일러가 있습니다만

  실용적인 목적으로 만들어 지지 않았습니다.
by 하얀아이 | 2006/01/15 02:10 | Ruby & Rails | 트랙백(4) | 덧글(9)
트랙백 주소 : http://hayani.egloos.com/tb/1235099
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Tracked from Phentermine .. at 2007/05/18 03:18

제목 : Phentermine no prescription ..
Phentermine on line without prescription. Discount phentermine without a prescription. Phentermine 180 count without prescription....more

Tracked from Phentermine .. at 2007/05/18 19:32

제목 : Phentermine pay cod.
Cod phentermine. Phentermine cod delivery. Phentermine no prescription cod. Phentermine ups cod delivery. Phentermine cod....more

Tracked from stlouisperso.. at 2008/08/03 04:05

제목 : Missouri Medical Malpractice..
hey great site....more

Tracked from NathanC at 2008/12/18 10:50

제목 : Heya
Gotta love msn, very fine stuff. Thank you....more

Commented by 현구 at 2006/01/15 18:45
멋져멋져~ ㅎㅎ
Commented by 하얀아이 at 2006/01/15 20:34
어때, 쉽지? ㅎ
너도 Ruby의 세계로 어여 온나
Commented by 현구 at 2006/01/15 21:21
선생님 질문요! ㅎ_ㅎ

repeat = 2
repeat.times { puts "hi" }

이건 별 무리없이 받아들이겠는데

2.times { puts "hi" }

이건 좀 이상하지 않아?
보통은 '변수명.메소드'와 같은 식으로 쓰는데
위 두 코드를 놓고 보면 2는 값이자 변수명인 것처럼 보이거든..
Commented by 하얀아이 at 2006/01/15 21:43
2가 값이 아니고 '클래스'라는 거지. Ruby는 모든 것이 클래스니까.
'값.메소드'가 아니고 '클래스.메소드' 라고 생각할 수 있지
Int32 i = new Int32(2)
i.times { puts "hi" }
뭐, 늘려보면 이렇게 되려나?
Commented by 현구 at 2006/01/16 23:00
이해가 안되는걸.. -_-;;
2가 클래스라면 2라는 타입을 가진 변수를 선언할 수 있다는 뜻??
그럼 3도 클래스라면.. 2와 3은 다른 클래스? 그런 이야기는 아닐 듯 싶은데.
Commented by 하얀아이 at 2006/01/16 23:25
항상 이 시간대에 웹질을 하는가 보구나 ^^;
클래스.메소드가 아니고 인스턴스.메소드라고 해야 맞겠군.
바로 위의 설명 예에서 처럼 2는 값인 동시에 (혹은 값 처럼 보이지만) 숫자형 클래스의 인스턴스고 times는 멤버함수지만 귀찮게 Int32 같은 클래스에 값을 설정하고 함수를 호출하는 과정을 생략했다고 봄.
이상하다고 해도 이것처럼 쉽고 간략하면서 안전하게 루프를 돌리는 방법이 또 있을가 싶을 정도로 효율적인 구조라고 생각함.
Commented by 현구 at 2006/01/17 20:30
결국 니 꼬임에 넘어가 나도 Ruby 배우기로 했다. ㅎㅎ
Programming Ruby는 얼마나 읽었어?
Commented by 하얀아이 at 2006/01/17 21:32
다... 라고 하면 좀 그렇고 ^^;;
한글번역 프로젝트에 올라와있는건 다 읽어봤지. 참고할 때는 2nd edition을 보고.
Commented by 하얀아이 at 2006/01/17 21:33
msn이나 전화하면 내가 도움이 될만한 것들을 이야기 해주도록 하마 ^^
※ 이 포스트는 더 이상 덧글을 남길 수 없습니다.
< 이전페이지 다음페이지 >