Skip to main content

Function กับ Go

การประกาศ Function

จากตัวอย่างในบทที่ 1 ที่เราทำเรื่อง sayHello ไป

package main

import (
"fmt"
)

func sayHello() {
fmt.Println("Hello World")
}

func main() {
sayHello()
sayHello()
sayHello()
}

Function คือ block ของ code ที่จะทำการรวมชุดคำสั่งเอาไว้และทำการเรียกใช้คำสั่งนั้นใหม่ผ่านชื่อที่มีการตั้งเอาไว้ (กฎเดียวกับการตั้งชื่อตัวแปร) ผ่าน keyword func

Function นั้นจริงๆแล้วมีวัตถุประสงค์การใช้งานคือ

  1. Modularity = ทำการ breakdown คำสั่งขนาดใหญ่ให้เล็กลง เพื่อให้ code ดูเรียบง่ายขึ้น
  2. Reuse = สามารถสร้างชุดคำสั่งเพื่อให้สามารถกลับมาใช้ซ้ำได้
  3. Parameters and Return Values = function สามารถส่งค่าเข้าไปใน function (เรียกว่า parameter) และส่งค่ากลับออกมาจาก function ได้ ซึ่งจะส่งผลทำให้ function มีคุณสมับัติในการ process และ transform ข้อมูลออกมาด้วยเช่นกัน

ทีนี้ function จากด้านบนนี้เป็น function ประเภท function แบบไม่มีการรับค่า หรือคืนค่าใดๆ

โดยโครงสร้างของ function จริงๆนั้นจะประกอบด้วยกันทั้งหมด 3 ส่วนใหญ่ๆคือ

func functionName(parameter1 type1, parameter2 type2) returnType {
// Function body
// Return statement (if the function has a return type)
}
  1. functionName = ชื่อ function
  2. parameter = ค่าที่เราจะทำการส่งเข้า function เข้าไป
  3. returnType = ค่าที่เราจะทำการส่งกลับออกมา หลังจากที่ดำเนินการใน function เรียบร้อย

มาลองดูผ่านตัวอย่างการใช้งาน parameter และ returnType ของ function กัน

parameter function

มาลองรับ parameter และส่ง parameter เข้า function กัน

ตัวอย่าง

  • ลองทำ function สำหรับการแสดงผลโดยรับชื่อเข้าไป
package main

import "fmt"

func sayHello(name string) {
fmt.Printf("Hello %s\n", name)
}

func main() {
sayHello("mike")
sayHello("mikelopster")
sayHello("tanitphon")
}

ผลลัพธ์ go-control-01

การ return ค่า function

ทีนี้มาลองเพิ่มการ return ค่ากลับไปบ้าง

package main

import "fmt"

func add(a int, b int) int {
return a + b
}

func main() {
number1 := 3
number2 := 5
sumNumber := add(number1, number2)
fmt.Println(sumNumber)
}

ผลลัพธ์ go-control-01

receiver method (นิยาม method ใน go)

ทีนี้สิ่งแรกที่เราต้องรู้ (สำหรับคนที่เรียน OOP หรือใช้ภาษา OOP อย่าง Java มา) นั่นคือ

"Go ไม่มี Class" = เราจะไม่มี method ที่สามารถเข้าถึง element ใน object แบบเจาะจงได้

  • นึกถึงตอนใช้ Class ปกติเราจะมีการสร้าง Class ต้นแบบไว้หนึ่งอัน
  • เสร็จแล้วเราสร้าง Object โดยการอ้างอิงถึง Class ต้นแบบและนำมาใช้สำหรับข้อมูล Object ตัวนั้นออกมา

เราลองนึกถึงเคสง่ายๆ เช่นเรามี Student ที่เราเก็บ ชื่อจริง (firstname) และ นามสกุล (lastname) เอาไว้

  • แล้วเราอยาก implement ตัว function getFullname คู่เข้าไปกับตัวนั้น เพื่อให้สามารถแสดง fullname ข้อมูลชุดนั้นมาได้

ถ้าเป็นเคสของ javascript เราจะสามารถแบบนี้ได้

const student = {
firstname: 'mike',
lastname: 'lopster',
getFullname: () => `${this.firstname} ${this.lastname}`
}

student.getFullname()

คำถามคือ แล้วใน go ละ ? เราสามารถทำสิ่งนี้ได้ยังไง = คำตอบก็คือ เราต้องทำเป็น method ขึ้นมา

  • method คือ function "ที่มี scope"
    • ใน go จะมองว่า function คือกลุ่มของ code ที่รวมชุดคำสั่ง
    • แต่จะมอง method เป็นเหมือน function ที่มี scope ของ object นั้น

ซึ่งการทำให้ function กลายเป็น method ได้ จะต้องมีการเพิ่ม "receiver argument" เข้าไปหน้า function เพื่อเป็นการระบุ type ของ method และเราสามารถ instances method นั้นใหม่ "เสมือนว่า" เป็นการ new Object ในภาษา OOP ได้เลย

โดยคุณสมบัติของ method (เมื่อมีการประกาศใช้เป็น method นั้น) จะมีดังนี้

  1. Tied to a Type = method จะถูก defined ผูกมัดไปกับ type ที่ประกาศไว้ใน method เสมอ เมื่อมีการ instances ตัวแปรใหม่ขึ้นมา
  2. Receiver Argument = เป็นเพียงการระบุถึงประเภทของ instance ที่ method เรียกถึงเท่านั้น
  3. สามารถ access เข้าถึง property ของ receiver ได้ (เหมือนกับการ access object ใน oop)

เรามาลองดูตัวอย่างผ่านตัวอย่าง student กัน

package main

import (
"fmt"
)

// Define the Student struct
type Student struct {
Firstname string
Lastname string
}

// Method with a receiver of type Student
// This method returns the full name of the student
func (s Student) FullName() string {
return s.Firstname + " " + s.Lastname
}

func main() {
student := Student{
Firstname: "Mike",
Lastname: "Lopster",
}

// Call the FullName method on the Student instance
fullName := student.FullName()
fmt.Println("Full Name of the student:", fullName)
}

อีกตัวอย่างคลาสสิค

package main

import (
"fmt"
)

// Define a struct type
type Rectangle struct {
Length float64
Width float64
}

// Method with a receiver of type Rectangle
func (r Rectangle) Area() float64 {
return r.Length * r.Width
}

func main() {
rect := Rectangle{Length: 10, Width: 5}

// Call the Area method on Rectangle instance
area := rect.Area()
fmt.Println("Area of rectangle:", area)
}

interface

อีกคุณสมบัติหนึ่งที่ Go ได้เตรียมไว้คู่กับ method คือ interface

  • interface คือการระบุ set ของ method ที่ต้องมีภายใต้ interface นั้นๆ
  • interface เป็นเหมือนต้นแบบของ method ว่า method นั้นควรจะต้องมีคุณสมับบัติอะไรบ้าง (เป็นเหมือนการกำหนดต้นแบบเอาไว้)
    • เช่น สมมุติเรามี class สำหรับสร้าง สี่เหลี่ยม, สามเหลี่ยม, วงกลม
    • ทั้ง 3 class นี้ก็มีการเก็บขนาดที่แตกต่างกัน แต่เราอยากให้ทั้ง 3 class นี้ ควรมี method ที่มีคุณสมบัติในการหาพื้นที่เหมือนกัน
    • ทั้ง 3 class เลยต้องสร้าง method สำหรับการคำนวนพื้นที่ออกมา ที่ไม่เหมือนกันออกมา
    • ซึ่งการกำหนดว่าทั้ง 3 class ควรต้องมี method ในการหาพื้นที่ ออกมา เราเรียกสิ่งนี้ว่า "interface" = ระบุแค่สิ่งที่ต้องมี แต่สิ่งที่ต้องมีนั้นทำอะไรก็จะเป็นการ implement ผ่าน method อีกที
    • เราเรียกคุณสมบัตินี้ว่า "Polymorphism" ใน Go คือความสามารถในการจัดการ object ให้มีหลากหลายรูปแบบจากการสืบทอดผ่าน interface ได้
  • ใครเรียนรู้ OOP มา มันคือ concept เดียวกันกับการใช้ implements ในพวกภาษา OOP

โดย กฎการใช้ interface ของ go คือ

  1. method set ทั้งหมดต้องถูก implement = ถ้ามี method ไม่ถูก implement ใน interface นั้น จะเท่ากับ ไม่สามารถเรียกผ่าน interface ได้
  2. เมื่อไหร่ก็ตามที่มี method ครบตาม interface = เป็นการ implement interface นั้นโดยอัตโนมัติ (ไม่ต้องมีประกาศเพิ่ม)
  3. คำแนะนำ go คือ interface ควรลงท้ายด้วย -er เพื่อให้สามารถแยกระหว่าง interface กับ type อื่นๆได้ง่ายขึ้น (อันนี้เป็นคำแนะนำเฉยๆ) = มันใช้สำหรับการอธิบาย action ที่เกิดขึ้นของ interface เพิ่มเติมได้ด้วย
package main

import "fmt"

// Speaker interface
type Speaker interface {
Speak() string
}

// Dog struct
type Dog struct {
Name string
}

// Dog's implementation of the Speaker interface
func (d Dog) Speak() string {
return "Woof!"
}

// Person struct
type Person struct {
Name string
}

// Person's implementation of the Speaker interface
func (p Person) Speak() string {
return "Hello!"
}

// function that accepts Speaker interface
func makeSound(s Speaker) {
fmt.Println(s.Speak())
}

func main() {
dog := Dog{Name: "Buddy"}
person := Person{Name: "Alice"}

makeSound(dog)
makeSound(person)
}