반응형

그냥 블록이라고 해도 되는지 모르겠습니다만...

irb(main):012:0> def calc(a,b)
irb(main):013:1> yield(a,b)
irb(main):014:1> end
=> nil
irb(main):015:0> calc(1,4){|a,b| puts a+b}
5
=> nil
irb(main):016:0> calc(2,3){|a,b| puts a*b}
6
=> nil


매우 비 실용적인 예제 입니다만...우선 함수 calc 를 정의했습니다. 그리고 a,b 두 값을 넣었고요. 그다음에 yield 를 실행하게 됩니다 yield 는 무엇일까요?
그 아래 실제 calc 함수를 사용한 예를 보면 '{' 중괄호로 된 부분이 yield 에 삽입되어 실행된다고 생각하면 됩니다. c언어로 따진다면 함수의 포인터 정도로 생각하면 이해가 될까 싶네요.

위에서 만든 calc 함수를 이용해서 다음과 같은 더하기 함수를 만들수도 있을겁니다.

irb(main):017:0> def add(a,b)
irb(main):018:1> calc(a,b){|a,b| puts a+b}
irb(main):019:1> end
=> nil
irb(main):020:0> add(10,10)
20

사용하기에 따라선 여러가지로 사용할 수 있겠지요.

yield 를 사용하지 않고 직접 인자로 받아 사용할 수도 있습니다.

irb(main):023:0> def calc2(*args, &action)
irb(main):024:1> action.call(args)
irb(main):025:1> end

action 이 바로 실제 수행될 코드를 가리킵니다. 이게 함수포인터와 더 비슷하다고 할 수 있겠네요. 이 경우는 call 명령으로 명시적으로 실행해 줍니다.

위에서 만든 calc2 함수는 이렇게 사용하면 됩니다.

irb(main):057:0> x=0
=> 0
irb(main):058:0> y=0
=> 0
irb(main):059:0> calc2(1,2,3,4,5){|a| a.each {|x| y+=x}}
=> [1, 2, 3, 4, 5]
irb(main):060:0> y
=> 15


마지막으로 lambda 입니다.

pow = lambda{|a,b| puts a**b}

제곱을 구하는 pow 를 정의합니다.
다음과 같이 사용하면 됩니다.

irb(main):068:0> pow.call(4,2)
16


새삼스럽게 이야기 하자면 중괄호는 do~end 로 사용할 수 있습니다. 한줄일땐 중괄호({) 여러줄일땐 do~end 를 쓰면 되죠. 아래와 같이 말이죠.

irb(main):030:0> sum=lambda do |a|
irb(main):031:1* c=0
irb(main):032:1> a.each {|b| c=c+b}
irb(main):033:1> return c
irb(main):034:1> end

사용방법은 당연히 똑 같습니다.

irb(main):039:0> sum.call(1..100)
=> 5050
irb(main):040:0> sum.call(1..1000)
=> 500500

'프로그래밍 > ruby' 카테고리의 다른 글

루비정리> 3. 클래스  (0) 2009.06.25
루비 정리> 2. 제어문과 반복문  (0) 2009.06.18
루비 정리> 1. 자료형  (0) 2009.06.13
객체지향 스크립트 언어 루비.  (0) 2008.01.25
반응형

루비는 모든것이 객체라고 했죠. 따라서 클래스는 매우 중요하겠죠. 객체지향 프로그램에 대해 여기서 주절주절 설명하는건 제 주제에도 넘은 짓이고 그렇게 간단하게 말할 수 있는게 아니기에 여기선 더 언급하지 않겠지만 클래스를 제대로 쓰기위해서는 객체지향 프로그래밍 방법을 제대로 익히는게 중요하다는걸 명심하시고 따로 수련해 두시길 부탁드립니다.

그리고 이부분도 irb로 시험해 볼 수도 있지만 불편한점이 있으므로 일반에디터로 파일을 작성해서 실행하는 방법으로 테스트 하는게 편하실 겁니다.

그럼 시작해보겠습니니다.

일단 클래스는 대충 이런 형태입니다.

class User
    def initialize(uid, name, ip)
        @uid = uid
        @name = name
        @ip = ip
    end
end  


클래스 이름은 대문자로 시작하고 함수명은 소문자로 시작해야 한다는것도 기억해 두시고요. initialize 라는 함수는 생성자 입니다. 객체가 생성될때 한번 실행되는 함수 입니다. 객체 생성시 초기화 작업이 필요하면 여기서 합니다.

일단 c언어 의 경우는 '{' 를 이용하고 python은 들여쓰기로 구분하지만 루비는 'end' 로 블럭을 만듭니다. def ~ end 로 클래스의 멤버함수를 만들죠.
변수앞에 @를 붙이는건 이 변수가 클래스의 멤버변수라는 표시입니다. 그러고 보니 설명하지 않은게 많네요. 다음기회에....

class User
    def initialize(uid, name, ip)
        @uid = uid
        @name = name
        @ip = ip
    end
    
    def printInfo()
        puts "ID = #{@uid} -- Name : #{@name}"
    end
end   

x = User.new("milk","john","000.000.000.000")
x.printInfo


위의 예제에 간단히 printInfo 라는 함수를 추가 했습니다.

그리고 객체 생성을 User.new 라는 방법으로 했죠. 생성자에 값도 넣어주고 말이죠.
x.printInfo 라는 부분을 보시면 아시겠지만 루비에선 넘기는 인자가 없으면 '(' 괄호는 사용하지 않아도 됩니다.

class User
    attr_reader :uid
    def initialize(uid, name, ip)
        @uid = uid
        @name = name
        @ip = ip
    end
    
    def printInfo()
        puts "ID = #{@uid} -- Name : #{@name}"
    end
end   

x = User.new("milk","john","000.000.000.000")
x.printInfo
puts "ID = #{x.uid}"
x.uid = "aaa"


추가된 부분이 보이시나요? 소스의 둘째 줄입니다. attr_reader 라는 문장이 보이시죠. 직접 변수에 대한 read 를 가능하게 해줍니다. 위 소스를 실행해 보면 결과는 이렇습니다.

ID = milk -- Name : john
ID = milk
user.rb:17: undefined method `uid=' for #<User:0x1d7b222> (NoMethodError)

읽기는 가능했지만 쓰기는 불가능 하네요. 쓰기 가능은 attr_writer 입니다.

다음은 클래스 변수와 클래스 함수 입니다.
간단히 이야기 하면 c++/java 의 static 과 비슷하다고 할 수 있겠습니다.

클래스 변수는 간단히 설명하면 이런겁니다.

class User
    @@usernum = 0
    attr_writer :uid
    def initialize(uid, name, ip)
        @uid = uid
        @name = name
        @ip = ip
        @@usernum+=1
    end
    def printUsernum()
        puts "Usernum = #{@@usernum}"
    end
end   

User.new("aaa","bbb","xx")
x = User.new("ccc","ddd","xx")
x.printUsernum


결과는

Usernum = 2


뭔지 아시겠나요? 간단히 말하자면 클래스끼리 공유하는 변수라고 할 수 있겠네요. @@usernum = 0 으로 만들어 주었고 0 값으로 초기화 시켜주었습니다. 그 후에 객체를 2번 생성했고 @@usernum 에 1을 더한 결과가 누적되어 @@usernum 변수 값이 2가 되었습니다.

멤버함수는

class User
    @@usernum = 0
    attr_writer :uid
    def initialize(uid, name, ip)
        @uid = uid
        @name = name
        @ip = ip
        @@usernum+=1
    end
    def printUsernum()
        puts "Usernum = #{@@usernum}"
    end
    
    def User.printClassname()
        puts "I'm User Class"
    end
end   

User.printClassname()

결과는

I'm User Class


뭐...이런겁니다. new 로 객체를 생성하지 않고 바로 쓸수 있는 함수...별거 아니죠.

public/private/protected 같은 접근 제한자들도 있는데 이거 설명은 안하겠습니다.....

마지막으로 클래스라면 빼놓을 수 없는 상속에 대해 이야기 하겠습니다

class User
    attr_writer :uid
    def initialize(uid, name, ip)
        @uid = uid
        @name = name
        @ip = ip
    end
   
    def printInfo()
        puts "ID = #{@uid} -- Name : #{@name}"
    end
end  

class ServiceUser < User

    def sendMessage(msg)
        puts "Message<#{@uid}> : #{msg}"
    end
   
end

su = ServiceUser.new("white","lily","123.456.678.123")
su.printInfo
su.sendMessage("Hello")


=begin
x = User.new("milk","john","000.000.000.000")
x.printInfo
puts "ID = #{x.uid}"
x.uid = "aaa"
=end


ID = white -- Name : lily
Message<white> : Hello

실행 결과는 위와 같습니다.

우선 '=begine' '=end' 블럭은 이전의 코드를 주석처리 한겁니다. 여러줄 주석은 저렇게 처리하시면 되고요. 주의할 점은 '=begin' 이나 '=end' 가 라인 맨 앞에 있어야 한다는 것입니다. 앞에 공백도 있으면 안됩니다.

User 클래스를 상속한 ServiceUser 란 클래스를 생성해 주었습니다. 별다르게 설명할 내용은 없네요.
참고로 루비는 다중상속이 안됩니다. 대신 모듈이란게 있는데 이것도 나중에 설명하도록 하겠습니다.


이상 마치겠습니다. 이번 객체부분은 사실 좀 부실한듯도 한데요. 다른 객체지향언어를 좀 써봤거나 조금은 안다는 가정하에 쓰여져서 그렇습니다. 때문에 루비만의 클래스 만드는 법에 치중한거고요.

객체지향 프로그램은 간단히 설명하기 어려운 만큼 죄송하지만 다른 문헌으로 철저히 공부해 주시길 부탁 드리겠습니다.

'프로그래밍 > ruby' 카테고리의 다른 글

루비정리> 4. Block  (0) 2009.06.29
루비 정리> 2. 제어문과 반복문  (0) 2009.06.18
루비 정리> 1. 자료형  (0) 2009.06.13
객체지향 스크립트 언어 루비.  (0) 2008.01.25
반응형
2. 제어문과 반복문

가장 흔히 쓰이는게 if 문이죠? 먼저 다루어 보도록 하겠습니다.

irb(main):027:0> a=1
=> 1
irb(main):028:0> puts "a=1" if a==1
a=1
=> nil
irb(main):029:0> if a==1 then puts "a=1"
irb(main):030:1> end
a=1
=> nil
irb(main):031:0> if a==1 then puts "a=1" end
a=1
=> nil
irb(main):032:0> if a==1
irb(main):033:1> puts "a=1"
irb(main):034:1> end
a=1
=> nil


대강결과는 이렇군요. 한줄로 쓸땐 then 을 쓴다는것과 끝은 end 로 끝나야 된다는 정도를 제외하곤 다른 언어들과 큰차이는 없습니다.

다만 이런 형식의 문장은 처음봤을땐 제 경우는 좀 놀랍더군요. 'puts "a=1" if a==1'  조건문은 언제나 앞에 써야 한다는 고정관념을 날려버렸던 문장이었습니다. 그러고 보니 perl에서도 이게 가능했나 안했나 가물가물 하군요.

이번엔 for 문과 each 문을 보도록 하겠습니다.

irb(main):049:0> a=0
=> 0
irb(main):050:0> (1..100).each {|x| a+=x}
=> 1..100
irb(main):051:0> a
=> 5050


흔히 쓰는 1부터 100까지의 합을 구하는 문제입니다. 일단 a 변수에 합계를 더할테니 0으로 초기화 시키고
(1..100) 은 range 값입니다. 즉 1부터 100까지 숫자를 나타내는 겁니다. 1부터 50까지면 (1..50) 으로 쓰면 되겠지요.
루비는 모든것이 객체라는 말을 했었지요? 따라서 (1..100) 도 객체이고 그런 객체의 each 문을 사용한겁니다. each문을 한줄로 쓸때는 저렇게 '{' 중괄호를 이용합니다. 여러줄로 쓸때는 do~end 를 사용하죠.

irb(main):056:0> (1..100).each do |x|
irb(main):057:1* a+=x
irb(main):058:1> end
=> 1..100
irb(main):059:0> a
=> 5050


이런식으로 쓰면 됩니다.

for 문을 써보도록 하겠습니다.

irb(main):075:0> a=0
=> 0
irb(main):076:0> for x in (1..100)
irb(main):077:1> a+=x
irb(main):078:1> end
=> 1..100
irb(main):079:0> a
=> 5050


아마 python을 좀 보신분이라면 익숙하실 것 같습니다. 내용은 굳이 설명할 필요도 없겠지요.

혹시나 싶어서 이야기 하자면 for 문이나 each문에서 숫자를 예로 들었는데 당연히 숫자가 아닌것도 가능합니다.

irb(main):045:0> for x in ["a","b","c","d"]
irb(main):046:1> puts x
irb(main):047:1> end
a
b
c
d


리스트의 값에서 문자를 하나씩 가져옵니다.

while 문 역시 다른 언어들과 비슷합니다.

irb(main):023:0> x=0
=> 0
irb(main):024:0> while x<10 do
irb(main):025:1* x+=1
irb(main):026:1> puts x
irb(main):027:1> break if x==5
irb(main):028:1> end
1
2
3
4
5
=> nil


이 예는 break 까지 설명하기 위해 적었습니다. x가 5이면 루프를 탈출합니다. 다른언어에도 많이 있죠? 이 외에도 next 나 redo 가 있습니다. 사용방법은 영어 그대로이니 따로 설명안하겠습니다.

그외에 while 문과 비슷한 until 문이라던가 if 문과 비슷한 unless 문도 있지만 생략하겠습니다. 대충 짐작하실수 있을거라고 생각하고요...

마지막으로 반복문을 좀 보충해 보겠습니다. 다른언어에 없는 사용법입니다.

irb(main):014:0> 3.times  do
irb(main):015:1* print "hi!!!  "
irb(main):016:1> end
hi!!!  hi!!!  hi!!!  => 3


숫자.times 하고 블럭을 만들면 그 블럭이 숫자만큼 반복 실행 됩니다. 말그대로 숫자만큼 반복해라...라는게 되는거죠.
여기선 puts 대신 print를 썼는데 결과를 보시면 아시겠지만 print 는 줄바꿈을 하지 않습니다.

irb(main):023:0> 1.upto(10) do |x|
irb(main):024:1* a+=x
irb(main):025:1> end
=> 1
irb(main):026:0> a
=> 55


위에서 x 값은 1부터 10까지 값을 갖게 됩니다. 굳이 이렇게 쓸일은 없을지도...

그러면 1부터 10까지의 짝수의 합은 어떻게 구할 수 있을까요?

irb(main):038:0> a=0
=> 0
irb(main):039:0> 0.step(10,2) do |x|
irb(main):040:1* a+=x
irb(main):041:1> end
=> 0
irb(main):042:0> a
=> 30


step 을 쓰면 되겠군요. x 값은 0부터 10까지 2씩 더해 갑니다.


'프로그래밍 > ruby' 카테고리의 다른 글

루비정리> 4. Block  (0) 2009.06.29
루비정리> 3. 클래스  (0) 2009.06.25
루비 정리> 1. 자료형  (0) 2009.06.13
객체지향 스크립트 언어 루비.  (0) 2008.01.25
반응형
일단 서론...

루비 언어에 대해 블로그에 정리를 해 두고자 합니다.
절대로!!! 강좌가 아닙니다. 제 나름대로의 정리 입니다. 왜냐 하면 저도 루비를 잘 모르기 때문이지요. 사실 언어를 이것저것 보다 보면 그런대로 쓸 수는 있어도 정말 그 특성을 잘 파악해서 '잘' 쓰기는 쉽지 않다는 생각이 듭니다. 하지만 프로그램이라는것, 프로그램 언어라는건 사람이 쓰기 편하기 위해 만든거니까 설령 좀 어색하더라도, 효율적이지 않더라도 일단 원하는대로 작동 되면 된다고 생각하고 있습니다. 최적화야 그 다음에 해도 되는거고요.

어쨌던...조금씩 정리 해 갈까 합니다.

그럼 본론으로 넘어가도록 하죠.



루비의 interactive shell 인 irb 를 이용해서 설명을 하도록 하겠습니다.

루비에서는 특별한 변수 선언은 필요하지 않습니다.

그냥 다음과 같이 사용하면 됩니다.
뭐든 스트링 출력이 기본이죠. ^^;

irb(main):001:0> s = "Hello, ruby!!!"
=> "Hello, ruby!!!"
irb(main):002:0> puts s
Hello, ruby!!!
=> nil


변수 s 에 string을 할당하고 puts 명령으로 출력했습니다.

irb(main):004:0> puts "2009/06/01 #{s}"
2009/06/01 Hello, ruby!!!


위 와 같이 출력시에 변수를 사용하고 싶으면 #{var} 를 사용해서 출력할 수 있습니다.

irb(main):005:0> a=1
=> 1
irb(main):006:0> a.class
=> Fixnum


숫자도 다음과 같이 넣어주면 됩니다. 루비는 모든것이 객체입니다. a 변수에 1 을 넣고 a 가 어떤 객체인지 알아보았더니 Fixnum이라는 군요. 그럼 소숫점 값을 넣어보죠.

irb(main):007:0> a=1.1
=> 1.1
irb(main):008:0> a.class
=> Float


음...Float 라는군요. 이번엔 음수 값을 넣어 볼까요?

irb(main):009:0> a=-1
=> -1
irb(main):010:0> a.class
=> Fixnum
irb(main):011:0> a.abs
=> 1


a 가 객체라는걸 확실히 알 수 있겠죠? a.abs 라고 했더니 음수값을 없애 버렸습니다. ^^;

다음은 리스트와 해시를 알아보도록 하죠. 꼭 필요한것이니까요.

리스트는 다음과 같이 만듭니다.

irb(main):012:0> a=[1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):013:0> a[0]
=> 1
irb(main):014:0> a[4]
=> 5
irb(main):015:0> a[5]
=> nil


다른언어에서 배열과 같지요. 뭐...그렇습니다. 대부분 언어에서 그렇듯 0 에서 부터 시작하고요. 때문에 a[5] 값은 nil 이지요. nil은 null 값을 표현하는 루비의 방식입니다.

파이썬등을 해 보셨다면 다음 구문등도 익숙하실텐데요.

irb(main):016:0> a[1..3]
=> [2, 3, 4]
irb(main):017:0> a[-1]
=> 5


이런식으로 다룰수도 있습니다. 보시면 뭔지 아시겠지요?

위에선 리스트를 ',' 로 구분했습니다. 하지만 다음과 같이 정의 할 수 도 있습니다.

irb(main):018:0> a = %w{a b c d e f, g}
=> ["a", "b", "c", "d", "e", "f,", "g"]
irb(main):019:0> a[3]
=> "d"
irb(main):020:0> a[5]
=> "f,"


f 옆의 ',' 는 저 위에서 쓰인 ',' 와 용도가 다릅니다. 리스트의 구분자가 아니라 그냥 문자죠. 그래서 a[5]를 출력해 보니 'f,' 로 ',' 까지 출력되는것을 볼 수 있습니다. perl에도 비슷한 방법이 있는데 이런면에선 perl 이 생각나는군요.

그외에 리스트를 스택이나 큐처럼 써보죠. 예제만 간단히 적습니다.

irb(main):001:0> a=[1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):002:0> a.push(6)
=> [1, 2, 3, 4, 5, 6]
irb(main):003:0> a.pop
=> 6
irb(main):004:0> a
=> [1, 2, 3, 4, 5]
irb(main):005:0> a.shift
=> 1
irb(main):006:0> a
=> [2, 3, 4, 5]


위의 결과만 보셔도 아실거라고 믿습니다.

해시도 다른언어와 비슷합니다.

irb(main):033:0> a = {"apple" => "red",
irb(main):034:1*      "banana" => "yellow"}
=> {"apple"=>"red", "banana"=>"yellow"}
irb(main):035:0> a["banana"]
=> "yellow"


이런식이죠.

값을 좀더 추가 해 볼까요?

irb(main):036:0> a["strawberry"] = "red"
=> "red"
irb(main):037:0> a
=> {"apple"=>"red", "banana"=>"yellow", "strawberry"=>"red"}

이렇게 추가하는 방법도 있습니다. strawberry 가 추가 되어 있는게 보이실 겁니다.

irb(main):038:0> a.keys
=> ["apple", "banana", "strawberry"]


이렇게 하면 해시의 key 들만 출력됩니다.


'프로그래밍 > ruby' 카테고리의 다른 글

루비정리> 4. Block  (0) 2009.06.29
루비정리> 3. 클래스  (0) 2009.06.25
루비 정리> 2. 제어문과 반복문  (0) 2009.06.18
객체지향 스크립트 언어 루비.  (0) 2008.01.25

+ Recent posts