Go Interfaces

Back to Go Index

Interface Concept

Interface คือรูปแบบลักษณะที่ตกลงร่วมกันและเข้ากันได้ (method signature)

Empty Interface

  • Go v1.8 ขึ้นไป any กับ interface{} เป็นตัวเดียวกัน ใช้เพื่อระบุว่า ใช้ได้กับทุก Type
func main() {
	var v any
 
	v = 36
	fmt.Println(v)
 
	v = "hello"
	fmt.Println(v)
}

Type Assertion

ใช้ Type assertion เพื่อให้ type ตรงกันกับ function

func show(val int) { // int
	i := val + 2
	fmt.Println(i)
}
 
func main() {
	var v any
	v = 36
	show(v.(int)) // type assertion
}

Type Assertion with Safety Check

หรือเปลี่ยนให้ type parameter เป็น any ก็จะใช้ได้กับทั้งหมด แต่จะไม่สามารถดำเนินการแบบ int ใน function ได้เหมือนเดิม ต้องทำ Type assertion

ใช้ตัวแปร ok เพื่อเช็ค type ก่อน ป้องกันไม่ให้เกิด runtime error ตอน assert type ได้

func show(val any) { // any
	i, ok := val.(int) // type assertion checking
	if ok {
		i = i + 1
		fmt.Println(i)
	} else {
		fmt.Println("Not int")
	}
}
 
func main() {
	var v any
	v = 36
	show(v)
}

Type Switch

ใช้ switch case เพื่อจัดการกับแต่ละ Type ได้ tips

func show(val any) {
	switch v := val.(type) { // switch case type
	case int:
		i := v + 1
		fmt.Println("int:", i)
	case string:
		s := v + "Hi"
		fmt.Println("string:", s)
	default:
		fmt.Println("unknown")
	}
}
 
func main() {
	var v any
	v = 36
	show(v)
}

Type Assertion vs Type Conversion

ทั้งสอง Concept นี้ ใช้เพื่อแปลงค่าจาก type หนึ่งไปเป็น type ใหม่ แต่มีจุดแตกต่างดังนี้

Type AssertionsType Conversions
Syntaxx.(T)T(value)
Use caseExtract a value of a specific type from an interface valueExplicitly convert a value of one type to another
ResultReturns the value of the asserted type and a boolean indicating whether the assertion succeeded or failedReturns a new value of the specified type
FailureFails if the value being asserted is not of the specified typeFails if the value being converted is not compatible with the target type
PerformanceGenerally slower than type conversions due to additional runtime checksGenerally faster than type assertions because they involve a simple conversion operation

Interface Implementation

  • ประกาศ interface แล้วตั้งชื่อว่า promotion ที่มี method signature ไว้
  • ประกาศ struct ชื่อ course แล้วมี 2 method คือ discount() และ info()
  • จะเห็นว่า course เป็นไปตาม interface promotion เพราะมี method discount() จึงเป็นการ implement อัตโนมัติโดยไม่ต้องเขียน และไม่ได้สนใจ info()
  • ดังนั้น sale() จึงรับ parameter course เข้ามา แล้วสามารถใช้ discount() ได้
  • แต่จะใช้ info() ไม่ได้ เพราะ course เข้ามาใน sale() ในฐานะ interface promotion
type promotion interface {
	discount() float64
}
 
type course struct{}
 
func (c course) discount() float64 {
	return 0.1
}
 
func (c course) info() {
	fmt.Println("Course info", c)
}
 
func sale(val promotion) {
	fmt.Printf("Sale: %#v\n", val.discount())
}
 
func main() {
	v := course{}
	sale(v)
}

Embedding Interface

เราสามารถนำ Interface มาหลอมรวมกันใน Interface ตัวอื่นๆ ได้

  • ประกาศ interface ตั้งชื่อว่า presenter โดยรวม promotioner และ infoer
  • course เป็นไปตาม interface presenter ที่มีทั้ง method discount() และ info() จึงเป็นการ implement อัตโนมัติ
  • summary() จึงสามารถรับ course เข้ามาได้
type promotioner interface {
	discount() float64
}
 
type infoer interface {
	info()
}
 
type presenter interface { // Embedding Interface
	promotioner
	infoer
}
 
type course struct{}
 
func (c course) discount() float64 {
	return 0.1
}
 
func (c course) info() {
	fmt.Println("Course info", c)
}
 
func summary(val presenter) {
	fmt.Printf("Sale: %#v\n", val.discount())
	val.info()
}
 
func main() {
	v := course{}
	summary(v)
}

Related: