Chuyển đến nội dung chính
Mô-đun 6 · Bài học 1 trong tổng số 526/50 trong khóa học~12 min
Bài học theo mô-đun (1/5)

Giao diện: xác định hành vi

giao diện trong Go là một tập hợp các chữ ký phương thức. Một giá trị thực hiện giao diện nếu nó có tất cả các phương thức đó — không implements, không extends, không đăng ký rõ ràng. Đó là mô hình thường được gọi là "gõ cấu trúc" hoặc "gõ vịt tĩnh": trình biên dịch kiểm tra sự phù hợp tại thời điểm biên dịch, nhưng dựa trên hình dạng, không phải trên tờ khai.

Khai báo một giao diện

Go
type Greeter interface {
    Greet() string
}

Quy ước: tên kết thúc bằng -er cho giao diện một phương thức (Reader, Writer, Stringer, Closer). Giao diện nhỏ (Phương thức 1–2) là thành ngữ: thư viện chuẩn có đầy đủ các giao diện nhỏ kết hợp với nhau (io.ReadWriter, io.ReadCloser, …).

Thực hiện ngầm

Go
type Person struct{ Name string }

func (p Person) Greet() string {
    return "ciao " + p.Name
}

// Person satisfies Greeter because it has the required method.
var s Greeter = Person{Name: "Ada"}
fmt.Println(s.Greet())

Không có từ khóa. Nếu loại có các phương thức, nó có thể được gán cho một biến của loại giao diện đó. Thế thôi.

Đa hình qua giao diện

Go
type Robot struct{ ID string }
func (r Robot) Greet() string { return "bip " + r.ID }

func greet(s Greeter) {
    fmt.Println(s.Greet())
}

greet(Person{Name: "Ada"})
greet(Robot{ID: "R2"})

greet chấp nhận bất kỳ loại nào đáp ứng Greeter. Đây là con đường đi thực hiện tính đa hình: không có thứ bậc, chỉ có khả năng.

Giao diện trống

Go
var x interface{} = 42
var y any = "ciao"   // any is the built-in alias of interface{}

interface{} (hoặc any kể từ Phiên bản 1.18) không yêu cầu phương thức nào, vì vậy bất kỳ phương thức nào giá trị thỏa mãn nó. Hữu ích cho các vùng chứa chung, nhưng để giải nén giá trị cụ thể bạn cần xác nhận kiểu hoặc chuyển đổi kiểu (bài học tiếp theo).

Bộ phương thức: giá trị so với bộ thu con trỏ (xem trước)

Nhớ lại Mô-đun 5:

  • Các phương thức có bộ nhận giá trị nằm trong bộ phương thức của cả T và *T.
  • Các phương thức có bộ nhận con trỏ CHỈ có trong bộ phương thức *T.

Hậu quả thực tế:

Go
type Counter struct{ N int }
func (c *Counter) Inc() { c.N++ }

type Incrementer interface { Inc() }

var i Incrementer = &Counter{}   // OK: *Counter has Inc()
// var j Incrementer = Counter{} // ERROR: Counter (value) does NOT

Khi một phương thức có bộ nhận con trỏ, bạn phải gán một con trỏ cho biến giao diện.

Hãy thử nó

tập thể dục#go.m6.l1.e1
Nỗ lực: 0Đang tải…

Xác định một giao diện Greeter bằng một chuỗi phương thức Greet() duy nhất.

Đang tải trình chỉnh sửa…
Hiển thị gợi ý

Cú pháp: `type Tên giao diện { Method(args) return }`.

Giải pháp khả dụng sau 3 lần thử

tập thể dục#go.m6.l1.e2
Nỗ lực: 0Đang tải…

Triển khai Greeter trên loại Robot mới có chuỗi ID trường; phương thức trả về 'bip' + ID.

Đang tải trình chỉnh sửa…
Hiển thị gợi ý

Không có `thực hiện`: chỉ xác định phương thức bằng chữ ký bên phải.

Giải pháp khả dụng sau 3 lần thử

Quiz#go.m6.l1.e3
Sẵn sàng

Bạn khai báo loại P đó triển khai giao diện Greeter như thế nào?

Go
type P struct{}
// ?
Tùy chọn trả lời

Tóm tắt lại

  • Giao diện = tập hợp các chữ ký phương thức; không implements.
  • Triển khai ngầm: chỉ cần có các phương thức có chữ ký phù hợp.
  • Thành ngữ: giao diện nhỏ (phương thức 1–2), tên trong -er.
  • interface{} / any: chấp nhận bất kỳ giá trị nào, mất an toàn về loại.
  • Bộ phương thức: bộ nhận con trỏ → chỉ *T thỏa mãn giao diện.
  • Go đa hình: tham số kiểu giao diện, không phân cấp.