Iterator

Iterators ไม่ใช่ความคิดดั้งเดิมของ ruby แต่ปกติ Iterators นั้นนิยมใช้ใน Object-oriented อยู่แล้ว ในภาษา Lisp ก็มีอยู่ด้วยเช่นกัน เพียงแต่ว่าไม่ได้ใช้คำเรียกว่า Iterators เนื่องจาก Iterator เป็นสิ่งที่ไม่คุ้นกันจึจำเป็นต้องอธิบายลงในรายละเอียด คำว่า Iterator หมายความว่าเป็นการทำซ้ำหลายครั้ง เมื่อเราต้องการจะเขียน code ที่เกี่ยวกับ Iterator บนภาษา C เราต้องใช้ for หรือ while

char *str;
for (str = "abcdefg"; *str != '\0'; str++) {
/* process a character here */
}

จาก code ที่ได้เห็นเป็นการทำ Iterator แจากตรงนี้สามารถอธิบายได้ว่า program จะทำการตรวจสอบค่าของ string กับ null ซึ่งต้องมีพื้นฐานเกี่ยวกับโครงสร้างของ string ทำให้ภาษา C ดูเหมือนเป็นภาษา Low-Level ส่วนภาษาที่เป็น High-Level นั้นก็จะมีคำสั่งที่ทำให้การทำงานง่ายขึ้น อย่าง shell script

#!/bin/sh

for i in *.[ch]; do
# ... here would be something to do for each file
done

shell script เป็นการเลือกเฉพาะไฟล์ .c และ .h มาเพื่อทำการอะไรอย่างนึง และมันก็ทำงานได้บน ภาษา High-Level แล้วอย่างนี้ต้องไปเขียนภาษา C เองทำไม แต่มีจุดสังเกตุเพิ่มเติม ในเมื่อ build in data-type มีการเตรียม iterator มาให้แล้วแต่คงเซ็งเราต้องเขียน iterator เองด้วยภาษา Low-Level เมื่อเรามีการสร้าง data type ของตัวเองขึ้นมา ใน OOP ผู้ใช้มักนิยมสร้าง data type ของตัวเองขึ้นมา นี่จึงเป็นปัญหา ดังนั้น OOP จึงมีสิ่งอำนวยความสะดวกต่างหรือแม้กะทั้ง Class พิเศษเพื่อจัดการ Iterator โดยเฉพาะ แต่ Ruby สามาีรถจัดการได้โดยตรงเลย Strings ใน Ruby มี Iterator ที่มีประโยชน์

ruby> "abc".each_byte{|c| printf "", c}; print "\n"

nil

each_byte เป็น Iterator ที่อยู่ในรูปของ string แต่ละตัวอักษรถูกแทนด้วยตัวแปรที่ชื่อว่า c หรือว่าจะแปลให้ดูคล้ายภาษา C ดังนี้

ruby> s="abc";i=0
0
ruby> while i
| printf "", s[i]; i+=1
| end; print "\n"

nil

each_byte iterator ก็ดูเหมือนว่าจะง่ายแล้วน่าใช้ ต่อถ้ามี string class ในอนาคต อีกหนึ่งประโยชน์ที่ได้รับคือมันง่ายที่จะแก้ไข ซึ่งก็เป็นข้อดีส่วนหนึ่งโดยทั่วไป อีกหนึ่ง Iterator ใน String คือ each_line

ruby> "a\nb\nc\n".each_line{|l| print l}
a
b
c
nil

การทำงานในรูปแบบนี้เหมือการทำงานที่พยามทำกันใน ภาษา C เลยคือการหา delimiter, การลบตัวอีกษร, ฯลฯ ซึ่งมันก็ทำได้ง่ายโดยการใช้ Iterator for ที่อยู่ในบทที่แล้วก็ทำ iteration ได้ด้วยวิธี each คำสั่ง each ฬน strings ก็ได้ผลลัพท์เหมือนข้างบนด้วยการเขียนดังนี้

ruby> for l in "a\nb\nc\n"
| print l
| end
a
b
c
nil

gเราสามารถใช้ retry ใน for ได้เพื่อให้ทำการทำ loop ใหม่ตั่งแต่ต้น

ruby> c=0
0
ruby> for i in 0..4
| print i
| if i == 2 and c == 0
| c = 1
| print "\n"
| retry
| end
| end; print "\n"
012
01234
nil

yield เป็นคำสั่งที่ให้กระโดออกไปทำคำสั่งอื่นๆนอก loop พอเสร็จให้กลับเข้ามาใน Loop ใหม่ ตัวอย่างจะเป็นการสร้าง iterator ที่ชื่อว่า repeat ซึ่งจะทำการทำซ้ำกับ code ที่เขียนต่อลงใน { } (block of code) ตามจำนวนที่ใส่ลงไป

ruby> def repeat(num)
| while num > 0
| yield
| num -= 1
| end
| end
nil
ruby> repeat(3) { print "foo\n" }
foo
foo
foo
nil

คราวนี้ลอง retry กับ yield ในการสร้าง iterator ที่ชื่อว่า WHILE

ruby> def WHILE(cond)
| return if not cond
| yield
| retry
| end
nil
ruby> i=0; WHILE(i<3) { print i; i+=1 }
012 nil

หวังว่าคงเข้าใน Iterator มากขึ้น มีข้อจำกัดอยู่นิดหน่อย แต่สามารถเขียน Iterator ขึ้นใช้เองได้ และเมื่อสร้าง data type ใหม่ขึ้นมามันก็ไม่ยากที่จะสร้าง iterator ขึ้นมาใช้งานซึ่งตัวอย่างข้างต้นก็ไม่เลวร้ายที่จะลองนำไปเป็นแนวทาง และจะยิ่งเข้าใจมากขึ้นถ้าได้ลองศึกษาเรื่อง Class ในต่อไป

Tue, 25 Jul 2006 16:19 Posted in

Tags , , , ,

  1. Avatar

    By maxdezign 4 months later:


    เจอลิ้งมาจาก เว็บพี่เหน่ง คับ ขอบคุณมากสำหรับบทความดีๆคับ แล้วจะแวะเข้ามาบ่อยๆคับผม

Comment Iterator


RSS