Khóa học go

Interfaces trong Go Lang

0 phút đọc

Interfaces là một khái niệm quan trọng trong Go, giúp tổ chức mã nguồn một cách hiệu quả và tái sử dụng mã dễ dàng. Interfaces cho phép bạn định nghĩa các phương thức mà một kiểu dữ liệu phải triển khai, giúp mã nguồn trở nên linh hoạt và dễ bảo trì hơn. Bài viết này sẽ cung cấp một cái nhìn tổng quan chi tiết về interfaces trong Go, bao gồm cú pháp, cách sử dụng, và các ví dụ minh họa cụ thể.

Khái Niệm Interfaces

Trong Go, một interface là một tập hợp các chữ ký phương thức (method signatures). Khi một kiểu dữ liệu cung cấp định nghĩa cho tất cả các phương thức trong interface, nó được coi là triển khai interface đó. Điều này tương tự như khái niệm interface trong lập trình hướng đối tượng (OOP).

Ví Dụ:

package main

import "fmt"

// Định nghĩa interface
type VowelsFinder interface {
    FindVowels() []rune
}

// Định nghĩa kiểu MyString
type MyString string

// MyString triển khai interface VowelsFinder
func (ms MyString) FindVowels() []rune {
    var vowels []rune
    for _, rune := range ms {
        if rune == 'a' || rune == 'e' || rune == 'i' || rune == 'o' || rune == 'u' {
            vowels = append(vowels, rune)
        }
    }
    return vowels
}

func main() {
    name := MyString("Sam Anderson")
    var v VowelsFinder
    v = name // có thể gán vì MyString triển khai VowelsFinder
    fmt.Printf("Vowels are %c", v.FindVowels())
}

Trong ví dụ trên, VowelsFinder là một interface với một phương thức FindVowels() []rune. Kiểu MyString triển khai interface này bằng cách cung cấp định nghĩa cho phương thức FindVowels.

Tạo và Sử Dụng Interfaces

Tạo Interface

Để tạo một interface trong Go, bạn sử dụng từ khóa type theo sau là tên của interface và từ khóa interface. Bên trong dấu ngoặc nhọn {}, bạn định nghĩa các chữ ký phương thức.

Ví Dụ:

package main

import "fmt"

// Định nghĩa interface
type Shape interface {
    Area() float64
    Perimeter() float64
}

Triển Khai Interface

Để triển khai một interface, một kiểu dữ liệu phải cung cấp định nghĩa cho tất cả các phương thức trong interface đó. Go không yêu cầu bạn phải sử dụng từ khóa implements như trong các ngôn ngữ khác. Việc triển khai interface được thực hiện một cách ngầm định.

Ví Dụ:

package main

import (
    "fmt"
    "math"
)

// Định nghĩa interface Shape
type Shape interface {
    Area() float64
    Perimeter() float64
}

// Định nghĩa kiểu Circle
type Circle struct {
    Radius float64
}

// Circle triển khai interface Shape
func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
    return 2 * math.Pi * c.Radius
}

// Định nghĩa kiểu Rectangle
type Rectangle struct {
    Width, Height float64
}

// Rectangle triển khai interface Shape
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

func main() {
    var s Shape

    s = Circle{Radius: 5}
    fmt.Printf("Circle Area: %f, Perimeter: %f\n", s.Area(), s.Perimeter())

    s = Rectangle{Width: 4, Height: 5}
    fmt.Printf("Rectangle Area: %f, Perimeter: %f\n", s.Area(), s.Perimeter())
}

Trong ví dụ này, CircleRectangle đều triển khai interface Shape bằng cách cung cấp định nghĩa cho các phương thức AreaPerimeter.

Interface Trống (Empty Interface)

Interface trống là một interface không có phương thức nào. Interface trống được biểu diễn bằng interface{}. Vì không có phương thức nào, mọi kiểu dữ liệu đều triển khai interface trống.

Ví Dụ:

package main

import "fmt"

func describe(i interface{}) {
    fmt.Printf("Type: %T, Value: %v\n", i, i)
}

func main() {
    describe(42)
    describe("hello")
    describe(true)
}

Trong ví dụ này, hàm describe nhận một tham số kiểu interface{}, cho phép nó chấp nhận mọi kiểu dữ liệu.

Type Assertion

Type assertion cho phép bạn truy cập giá trị cơ bản của một biến interface. Cú pháp của type assertion là i.(Type), trong đó i là biến interface và Type là kiểu dữ liệu mà bạn muốn truy cập.

Ví Dụ:

package main

import "fmt"

func main() {
    var i interface{} = "hello"

    s := i.(string)
    fmt.Println(s)

    s, ok := i.(string)
    fmt.Println(s, ok)

    f, ok := i.(float64)
    fmt.Println(f, ok)

    // f = i.(float64) // panic
    // fmt.Println(f)
}

Trong ví dụ này, i là một biến interface chứa giá trị chuỗi "hello". Type assertion i.(string) truy cập giá trị chuỗi cơ bản. Nếu type assertion không thành công, chương trình sẽ panic.

Sử Dụng Interface trong Hàm

Bạn có thể sử dụng interface làm tham số hoặc giá trị trả về của hàm, giúp hàm trở nên linh hoạt hơn.

Ví Dụ:

package main

import "fmt"

// Định nghĩa interface Describer
type Describer interface {
    Describe()
}

// Định nghĩa kiểu Person
type Person struct {
    Name string
    Age  int
}

// Person triển khai interface Describer
func (p Person) Describe() {
    fmt.Printf("%s is %d years old\n", p.Name, p.Age)
}

// Hàm nhận tham số kiểu Describer
func describe(d Describer) {
    d.Describe()
}

func main() {
    p := Person{Name: "Alice", Age: 30}
    describe(p)
}

Trong ví dụ này, hàm describe nhận một tham số kiểu Describer, cho phép nó chấp nhận mọi kiểu dữ liệu triển khai interface Describer.

Interface Lồng Nhau

Go cho phép bạn lồng các interface vào nhau, nghĩa là một interface có thể chứa các phương thức của một interface khác.

Ví Dụ:

package main

import "fmt"

// Định nghĩa interface Reader
type Reader interface {
    Read() string
}

// Định nghĩa interface Writer
type Writer interface {
    Write(string)
}

// Định nghĩa interface ReadWriter lồng Reader và Writer
type ReadWriter interface {
    Reader
    Writer
}

// Định nghĩa kiểu File
type File struct {
    content string
}

// File triển khai interface Reader
func (f *File) Read() string {
    return f.content
}

// File triển khai interface Writer
func (f *File) Write(content string) {
    f.content = content
}

func main() {
    var rw ReadWriter = &File{}
    rw.Write("Hello, World!")
    fmt.Println(rw.Read())
}

Trong ví dụ này, ReadWriter là một interface lồng chứa các phương thức của ReaderWriter. Kiểu File triển khai cả hai interface này.

Interface và Polymorphism

Interfaces trong Go cung cấp một cách để đạt được tính đa hình (polymorphism), cho phép bạn viết mã linh hoạt và tái sử dụng.

Ví Dụ:

package main

import "fmt"

// Định nghĩa interface Animal
type Animal interface {
    Speak() string
}

// Định nghĩa kiểu Dog
type Dog struct{}

// Dog triển khai interface Animal
func (d Dog) Speak() string {
    return "Woof!"
}

// Định nghĩa kiểu Cat
type Cat struct{}

// Cat triển khai interface Animal
func (c Cat) Speak() string {
    return "Meow!"
}

// Hàm nhận tham số kiểu Animal
func makeSound(a Animal) {
    fmt.Println(a.Speak())
}

func main() {
    dog := Dog{}
    cat := Cat{}

    makeSound(dog)
    makeSound(cat)
}

Trong ví dụ này, DogCat đều triển khai interface Animal, cho phép hàm makeSound chấp nhận cả hai kiểu dữ liệu này.

Kết Luận

Interfaces là một khái niệm quan trọng trong Go, giúp tổ chức mã nguồn một cách hiệu quả và tái sử dụng mã dễ dàng. Bài viết này đã cung cấp một cái nhìn tổng quan chi tiết về interfaces trong Go, bao gồm cú pháp, cách sử dụng, và các ví dụ minh họa cụ thể. Hiểu rõ về interfaces sẽ giúp bạn viết mã Go hiệu quả và dễ bảo trì hơn.

Avatar
Được viết bởi

TechMely Team

Gợi ý câu hỏi phỏng vấn

Gợi ý bài viết

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào

Khoá học javascript từ cơ bản đến chuyên sâuYoutube Techmely