Ôn tập: tập hợp tổng quát
Thuộc phần Lập trình hướng đối tượng trong hành trình GO của Coddy. Bài học 72 trên 107.
Thử thách
DễHãy xây dựng một cấu trúc dữ liệu Queue tổng quát để minh họa tất cả những gì bạn đã học về kiểu tổng quát trong Go! Khác với ngăn xếp (LIFO), hàng đợi tuân theo thứ tự vào trước, ra trước (FIFO): phần tử được thêm vào đầu tiên sẽ là phần tử được lấy ra đầu tiên.
Bạn sẽ tổ chức code trong hai tệp:
queue.go: Định nghĩa bộ sưu tập hàng đợi tổng quát.Tạo một struct tổng quát
Queue[T any]lưu trữ các phần tử bên trong. Hàng đợi của bạn cần hỗ trợ các thao tác sau:Enqueue(item T)- thêm một phần tử vào cuối hàng đợiDequeue() (T, bool)- xóa và trả về phần tử ở đầu hàng đợi, kèm theo một giá trị boolean cho biết thao tác có thành công hay không (trả về giá trị 0 vàfalsenếu hàng đợi trống)Peek() (T, bool)- trả về phần tử ở đầu hàng đợi mà không xóa phần tử đó (cách trả về giống như Dequeue)Size() int- trả về số lượng phần tử trong hàng đợiIsEmpty() bool- trả về true nếu hàng đợi không có phần tử nào
Đồng thời, tạo một hàm khởi tạo
NewQueue[T any]() *Queue[T]trả về con trỏ đến một hàng đợi trống đã được khởi tạo.main.go: Minh họa hàng đợi của bạn với các kiểu dữ liệu khác nhau, dựa trên đầu vào.Đọc một chỉ báo kiểu dữ liệu (
inthoặcstring), sau đó đọc một loạt lệnh để thực hiện trên hàng đợi. Mỗi lệnh nằm trên một dòng riêng:enqueue [value]- thêm giá trị vào hàng đợidequeue- xóa và in ra phần tử ở đầu hàng đợi (in raemptynếu hàng đợi trống)peek- in ra phần tử ở đầu hàng đợi mà không xóa phần tử đó (in raemptynếu hàng đợi trống)size- in ra kích thước hiện tại
Đọc các lệnh cho đến khi nhận được
done.
Đầu vào sẽ có dạng như sau:
- Dòng 1: Chỉ báo kiểu dữ liệu (
inthoặcstring) - Các dòng tiếp theo: Lệnh cho đến khi gặp
done
Ví dụ, với đầu vào:
int
enqueue 10
enqueue 20
enqueue 30
peek
dequeue
size
dequeue
dequeue
dequeue
doneĐầu ra của bạn sẽ là:
10
10
2
20
30
emptyVới đầu vào:
string
enqueue hello
enqueue world
size
peek
dequeue
peek
doneĐầu ra của bạn sẽ là:
2
hello
hello
worldHàng đợi của bạn cần hoạt động giống hệt nhau với cả kiểu số nguyên và kiểu chuỗi, qua đó cho thấy một cách triển khai tổng quát có thể xử lý nhiều kiểu cụ thể trong khi vẫn đảm bảo an toàn kiểu dữ liệu.
Tự làm thử
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Đọc chỉ báo kiểu dữ liệu
scanner.Scan()
typeIndicator := scanner.Text()
if typeIndicator == "int" {
// TODO: Tạo hàng đợi số nguyên bằng NewQueue[int]()
// Xử lý các lệnh cho hàng đợi số nguyên
for scanner.Scan() {
line := scanner.Text()
if line == "done" {
break
}
parts := strings.SplitN(line, " ", 2)
command := parts[0]
// TODO: Xử lý các lệnh: enqueue, dequeue, peek, size
// Với enqueue, chuyển giá trị từ parts[1] thành số nguyên
// Với dequeue/peek, in ra "empty" nếu hàng đợi trống
_ = command
}
} else if typeIndicator == "string" {
// TODO: Tạo hàng đợi chuỗi bằng NewQueue[string]()
// Xử lý các lệnh cho hàng đợi chuỗi
for scanner.Scan() {
line := scanner.Text()
if line == "done" {
break
}
parts := strings.SplitN(line, " ", 2)
command := parts[0]
// TODO: Xử lý các lệnh: enqueue, dequeue, peek, size
// Với enqueue, dùng giá trị chuỗi từ parts[1]
// Với dequeue/peek, in ra "empty" nếu hàng đợi trống
_ = command
}
}
// Các dòng này giúp tránh lỗi import không được sử dụng trong quá trình phát triển
_ = strconv.Atoi
_ = fmt.Println
}
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng OOP trong Go
Tệp bên ngoàiWorkspace và module trong GoPackage và importTên được export và không được exportGiới thiệu về OOP trong GoStruct như lớpĐịnh nghĩa phương thức cho structReceiver kiểu con trỏ và kiểu giá trịKhởi tạo structHàm khởi tạoÔn tập: máy tính đơn giản4Interface
Giới thiệu về interfaceTriển khai ngầm địnhInterface như một hợp đồngInterface rỗng (any)Khẳng định kiểuswitch kiểuKết hợp interfaceInterface Stringer và ErrorÔn tập: Máy tính hình học7Tính đóng gói
Trường được xuất và không được xuấtĐóng gói ở cấp packagePhương thức getter và setterẨn thông tin trong GoÔn tập: hồ sơ học sinh10Generics (Go 1.18 trở lên)
Giới thiệu về GenericsTham số kiểuRàng buộc kiểuStruct tổng quátGiải pháp thay thế cho phương thức tổng quátÔn tập: tập hợp tổng quát13Các mẫu thiết kế phần 1
Giới thiệu về mẫu thiết kếMẫu SingletonMẫu FactoryMẫu Abstract FactoryMẫu ObserverMẫu Strategy2Tìm hiểu chuyên sâu về kiểu dữ liệu và struct
Kiểu cơ bản và kiểu tổng hợpĐịnh nghĩa kiểu dữ liệu tùy chỉnhThẻ structStruct ẩn danhStruct lồng nhauGiá trị zero và giá trị mặc địnhÔn tập: sổ liên lạc5Ưu tiên kết hợp hơn kế thừa
Vì sao Go không có kế thừaNhập môn nhúng structTự động nâng phương thứcNhúng nhiều structNhúng và kết tậpChe khuất phương thức được nhúngÔn tập: hệ phân cấp nhân viên8Xử lý lỗi và lập trình hướng đối tượng
Giao diện errorCác kiểu lỗi tùy chỉnhBọc lỗi với fmt.ErrorfLỗi sentinelerrors.Is() và errors.As()Panic, defer và recoverÔn tập: trình phân tích tệp3Con trỏ và bộ nhớ
Cơ bản về con trỏ trong GoCon trỏ đến structTruyền theo giá trị và tham chiếuHàm new()Thu gom rác trong GoÔn tập: xây dựng danh sách liên kết6Đa hình trong Go
Đa hình qua interfaceĐịnh kiểu vịt trong GoQuy tắc thỏa mãn interfaceCác tập hợp đa hìnhTiêm phụ thuộcÔn tập: bộ xử lý thanh toán9Lập trình đồng thời và lập trình hướng đối tượng
Cơ bản về goroutineChannel và giao tiếpChannel có bộ đệm và không có bộ đệmCâu lệnh selectsync.Mutex và sync.RWMutexsync.WaitGroupThiết kế struct an toàn luồngÔn tập: worker poolTự luyện tập: Trình biên dịch Go online