เรื่องนี้ผมเคยเขียนไปแล้วแหละครับ แต่ที่ต้องนำออกมาไว้ตรงนี้ ก็เพราะเวลาที่ผม Monitor ดูพี่น้องเข้ามาตักตวงความรู้ในเว็บไซต์ของผม หลายคนอาจหาสิ่งที่ต้องการไม่เจอ เพราะตอนแรกที่ทำก็ไม่ได้คาดเลยว่า Ranking จะแจ่มอย่างนี้ ก็ทำเอามันๆ สนุกๆไป ไม่ได้คิดอะไรมาก ... ในหลายฉากหลายตอนผมเองได้กล่าวถึงเรื่องของ โปรแกรมย่อย (Sub Program) และ บางบทความก็เป็นเจตนาของผมเองที่ต้องการให้พี่น้อง ได้ทำการแปลงส่วนของการทำงานซ้ำๆให้กลายมาเป็นโปรแกรมย่อยแทน เพื่อจัดระเบียบ ลดความซ้ำซ้อนของโค้ด การตรวจสอบการทำงานของโปรแกรมทำได้ง่าย สามารถทำการตัดต่อเพื่อนำไปใช้ประโยชน์อย่างอื่นได้อย่างคล่องตัว จะเห็นได้ชัดเจนจากการเปิด หรือ ปิดการเชื่อมต่อข้อมูล ที่เก็บไว้ใน Module เมื่อนำไปใช้งานกับโปรเจคอื่นๆ ก็แค่ดึงไฟล์ Module (.BAS) ไปซ่ะงั้นเลย และดัดแปลงอีกเพียงเล็กน้อย ไม่ต้องมามัวงมโข่งเขียนขึ้นใหม่ให้เสียเวลา
แทบจะทุกๆภาษาคอมพิวเตอร์ โปรแกรมย่อยจะแบ่งออกเป็น 2 แบบคือ
- โปรแกรมย่อย ชื่อเรียกมันเยอะขึ้นกับภาษาที่ใช้ เช่น Sub Program, Sub Routine หรือ Procedure
- ฟังค์ชั่น (Function)
ทั้งสองแบบ บางที (บ่อยครั้ง) เราจะเรียกมันว่าเป็น "คำสั่ง" โดยกำเนิดเกิดจาก
- ติดมากับตัวแปลภาษา (Build In) เช่น Left$("ABC", 1), Mid$("ABC", 2, 1) หรือ MsgBox() ที่เราคุ้นเคยนี่แหละ ใน Visual Basic การเกิดเหตุการณ์ (Events) นั่นก็ถือว่าเป็นโปรแกรมย่อยได้ทั้ง 2 แบบเหมือนกัน ส่วน WinAPI มักจะเป็นเรื่องของฟังค์ชั่นครับผม
- สร้างขึ้นมาใหม่ เช่น ตัวอย่างของเรื่องนี้แหละครับ
ความเหมือนของทั้งสองแบบ คือ สามารถส่งค่า (Argument) ผ่านไปยังโปรแกรมย่อยได้ การส่งค่าก็มีอีก 2 แบบ คือ (คำว่า Argument กับ Parameter 2 ตัวนี้ ไม่ต้องไปสนใจใยดีมันนักหรอกครับ งง และ สับสนในชีวิตเปล่าๆ ... ขอให้รู้แต่เพียงว่า เมื่อมีการส่งค่าไปยังโปรแกรมย่อย และ ค่าที่ว่านี้จะต้องกำหนดให้เป็นตัวแปรชนิดเดียวกัน ... ก็พอแล้ว)
- Pass By Value คือ การส่งค่าผ่านตัวแปรไปตรงๆ เช่น
Private Sub Form_Load()
Dim NumberOfTimes As Integer
NumberOfTimes = 3
' พิจารณาเฉพาะตัวแปร NumberOfTimes พอครับ ... พี่น้อง
' ส่งค่า NumberOfTimes ซึ่งมีค่าเท่ากับ 3 ไปเลย
Call ShowMessage("Hello, World", NumberOfTimes)
Memory Address คือ ตัวเลขสมมุติให้เข้าใจง่าย ชื่อตัวแปร คือ มุมมองมาจากภาษาระดับสูง ... ไม่ใช่อินเฮอริตง ริแตนซ์ (Inheritance) เพื่อสืบทอดแต่อย่างใด ... แซว .Net น่ะ 55555+
' ให้แสดงผลค่าของ NumberOfTimes
MsgBox NumberOfTimes
' คำตอบคือ 3 เนื่องจากเป็นการส่งค่า (คัดลอกค่านั่นเแหละ) ไปโดยตรง ไม่ได้ถูกชี้ไปโดยตำแหน่งที่เก็บข้อมูล (Memory Address)
' ว่าง่ายๆ ตำแหน่งที่เก็บข้อมูลของ NumberOfTimes กับ Times มันอยู่คนละที่กัน ... ไม่เกี่ยวข้องกัน
End Sub
' ดังนั้นตัวแปรเพื่อรับค่า (Parameter) Times จึงมีค่าเท่ากับ 3 ด้วย (กระบวนการนี้เป็นการคัดลอกข้อมูลมาไงล่ะครับ ... พี่น้อง)
Sub ShowMessage(ByRef Text As String, ByVal Times As Integer)
Dim i As Integer
For i = 1 To Times
Debug.Print Text
Next
' เปลี่ยนค่าตัวแปร Times ให้เท่ากับ 23
Times = 23
End Sub
|
- Pass By Reference คือ การส่งค่าผ่านตำแหน่งหน่วยความจำ ... อธิบายเป็นตัวอักษรยากครับ ขอให้พิจารณาจากตัวอย่างแล้วกัน
Private Sub Form_Load()
Dim NumberOfTimes As Integer
NumberOfTimes = 3
' อันนี้เป็นการส่งค่าตำแหน่งที่เก็บข้อมูลของตัวแปร NumberOfTimes ไป
Call ShowMessage("Hello, World", NumberOfTimes)
ไปกระทำใดๆกับ ข้อมูลที่อยู่ในตำแหน่ง 10001 ก็จะมีผลให้เกิดการเปลี่ยนแปลงตามไปด้วย
' เมื่อกลับมาจากการทำงานโปรแกรมย่อย
MsgBox NumberOfTimes
' คำตอบคือ 23 เนื่องจากถูกชี้ไปโดยตำแหน่งที่เก็บข้อมูล (Memory Address)
' ตำแหน่งที่เก็บข้อมูลของ NumberOfTimes กับ Times มันอยู่ที่เดียวกันครับ ... พี่น้อง
' แต่ชื่อที่เราอ้างอิงถึงมันคนละชื่อกัน ก็เท่านั้น ... นี่แหละคือข้อดีของภาษาระดับสูง
' ใครที่ศึกษาภาษาระดับกึ่งต่ำกึ่งสูง เช่น Assembly มา อย่างนี้เรียกว่าขนมเลยครับ
End Sub
' รับค่า Argument เข้ามาแบบอ้างอิงตำแหน่ง
Sub ShowMessage(ByRef Text As String, ByRef Times As Integer)
Dim i As Integer
For i = 1 To Times
Debug.Print Text
Next
Times = 23
' เปลี่ยนค่าตัวแปร Times ให้เท่ากับ 23
' เมื่อเป็นการอ้างอิงตำแหน่งของการเก็บข้อมูล
' ดังนั้นเมื่อส่งค่าผ่าน ByRef ตำแหน่งของ Times กับ NumberOfTimes มันคือที่ๆเดียวกัน
' แต่ VB มันเป็นภาษาระดับสูง เราจึงไม่ต้องไปสนใจว่ามันอยู่ที่ Address ที่เท่าไร
End Sub
|
ความแตกต่างของ Sub Program และ Function ก็คือ
- Sub Program ไม่สามารถคืนค่ากลับมาได้
- Function สามารถคืนค่ากลับมาได้ (Return)
จงเชื่อในสิ่งที่ทำ ... How To and Do it ... Now
Option Explicit
Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Var() As Any) As Long
Private Sub Form_Load()
Dim NumberOfTimes As Integer
NumberOfTimes = 3
' ===================== Pass By Value ==================
Debug.Print "Pass by Value Address : " & VarPtr(NumberOfTimes)
Call ShowMessageByVal("Hello, World", NumberOfTimes)
' =====================================================
' ================= Pass By Reference ==================
Debug.Print "Pass by Reference Address : " & VarPtr(NumberOfTimes)
Call ShowMessageByRef("Hello, World", NumberOfTimes)
' =====================================================
End Sub
Sub ShowMessageByVal(ByRef Text As String, ByVal Times As Integer)
Debug.Print "Address ที่โปรแกรมย่อย : " & VarPtr(Times)
End Sub
Sub ShowMessageByRef(ByRef Text As String, ByRef Times As Integer)
Debug.Print "Address ที่โปรแกรมย่อย : " & VarPtr(Times)
End Sub
แสดงตำแหน่งข้อมูลทั้งแบบ Pass by Value (ตำแหน่งข้อมูลไม่ตรงกัน) และ แบบ Pass by Reference (ตำแหน่งข้อมูลอันเดียวกัน)
|