Go là ngôn ngữ lập trình biên dịch, kiểu tĩnh, được tạo ra tại Google. Nó tạo ra một tệp nhị phân gốc duy nhất, biên dịch trong vài giây, có bộ thu gom rác (garbage collection), và hỗ trợ lập trình đồng thời ngay trong ngôn ngữ qua goroutine và channel. Đất diễn chính của Go là phần mềm phía máy chủ: API, dịch vụ mạng, cùng các công cụ dòng lệnh và cloud dùng để vận hành chúng.
Đây là một chương trình Go hoàn chỉnh. Nhấn Chạy.
Mọi chương trình Go đều bắt đầu ở func main() trong package main. := khai báo một biến và tự suy ra kiểu của nó (ở đây là []string, một slice chứa chuỗi). range duyệt qua slice và đưa cho bạn chỉ số cùng giá trị. fmt và strings đến từ thư viện chuẩn, và thư viện này đủ lớn để nhiều chương trình không cần import gì thêm.
Go hay Golang: chuyện cái tên
Ngôn ngữ này tên là Go. "Golang" là biệt danh lấy từ trang web đầu tiên của dự án, golang.org (giờ trang chính thức nằm ở go.dev). Mọi người vẫn dùng tên này vì tìm "go" trên mạng thì ra đủ thứ trừ ngôn ngữ lập trình. Tài liệu chính thức viết "Go", nhưng "golang" là từ hầu như ai cũng gõ vào ô tìm kiếm, và hai tên là một. Không có sản phẩm hay biến thể "Golang" nào riêng cả.
Ai tạo ra Go và vì sao
Robert Griesemer, Rob Pike và Ken Thompson bắt đầu thiết kế Go tại Google vào năm 2007. Go ra mắt dưới dạng mã nguồn mở vào tháng 11 năm 2009, và Go 1.0 phát hành vào tháng 3 năm 2012.
Động lực rất thực tế. Các codebase C++ và Java khổng lồ của Google build rất lâu, sơ đồ phụ thuộc khó quản lý, và dù máy nhiều nhân cùng dịch vụ mạng đã thành chuyện bình thường, viết code đồng thời vẫn rất dễ sai. Thiết kế của Go trả lời thẳng vào những vấn đề đó:
- Build nhanh. Import phải ghi rõ, import không dùng đến là lỗi biên dịch, và trình biên dịch không phải phân tích lại header, nên chương trình lớn cũng build xong trong vài giây.
- Ngôn ngữ đơn giản. Ít từ khóa, một vòng lặp duy nhất (
for), không có kế thừa, không có ngoại lệ. Code do nhiều người viết thường trông giống nhau, giúp việc review trong team lớn dễ hơn. - Lập trình đồng thời là tính năng của ngôn ngữ. Khởi chạy một tác vụ đồng thời chỉ cần một từ khóa,
go, và channel cho các tác vụ trao đổi với nhau. - Triển khai dễ dàng. Kết quả build là một tệp nhị phân, bạn chỉ việc chép lên máy chủ. Tệp này thường được liên kết tĩnh; khi bật cgo, các package như
netcó thể liên kết với thư viện C của hệ thống, vàCGO_ENABLED=0sẽ tắt việc đó.
Go 1.0 còn đi kèm cam kết tương thích Go 1: chương trình viết cho Go 1.0 vẫn tiếp tục biên dịch và chạy được với các phiên bản 1.x sau này. Trên thực tế, nâng cấp bộ công cụ hiếm khi làm hỏng code của bạn, và đó là lý do lớn khiến các team tin dùng Go cho những dịch vụ chạy lâu năm.
Golang dùng để làm gì
Go mạnh nhất ở những chương trình giao tiếp qua mạng, chạy liên tục trong thời gian dài và cần dễ phát hành:
| Lĩnh vực | Ví dụ |
|---|---|
| Web API và microservice | Dịch vụ HTTP và gRPC, backend cho ứng dụng web và di động |
| Công cụ cloud và hạ tầng | Docker, Kubernetes, Terraform, Prometheus |
| Công cụ dòng lệnh | CLI cho lập trình viên, phát hành dưới dạng một tệp nhị phân cho mỗi nền tảng |
| Mạng | Proxy, bộ cân bằng tải, máy chủ DNS |
| Pipeline dữ liệu | Worker đọc hàng đợi, biến đổi bản ghi, ghi vào cơ sở dữ liệu |
Go kém phù hợp hơn với ứng dụng desktop có giao diện, ứng dụng di động, front end chạy trên trình duyệt, và các bài toán tính toán số hay học máy, nơi các hệ sinh thái khác có thư viện tốt hơn nhiều.
Tính năng chính, kèm code
Kiểu tĩnh có suy luận kiểu
Mỗi biến có một kiểu cố định lúc biên dịch, nhưng bạn hiếm khi phải viết kiểu ra. := tự suy ra:
Go không bao giờ tự ngầm chuyển đổi giữa các kiểu số. count * price không biên dịch được, vì một bên là int còn bên kia là float64; bạn phải tự viết float64(count). Nhờ vậy không có chuyện số bị cắt bớt hay mất độ chính xác mà bạn không hay biết.
Lỗi là giá trị
Go không có ngoại lệ (exception). Hàm nào có thể thất bại sẽ trả về một error ở vị trí kết quả cuối cùng, và nơi gọi hàm phải kiểm tra nó:
Mẫu if err != nil là dòng code dễ nhận ra nhất trong Go. Nó dài dòng, và đó chính là mục đích: mọi chỗ chương trình có thể thất bại đều hiện rõ ngay tại nơi xảy ra. Xem xử lý lỗi để biết cách bọc và kiểm tra lỗi.
Goroutine và channel
Goroutine là một hàm chạy đồng thời với phần còn lại của chương trình. Mỗi goroutine chỉ tốn vài kilobyte stack, nên chạy hàng nghìn goroutine là chuyện bình thường. Channel truyền giá trị giữa các goroutine một cách an toàn:
Ba goroutine chạy đồng thời, nên ba dòng có thể in ra theo bất kỳ thứ tự nào. Chạy vài lần, bạn có thể thấy thứ tự khác nhau. main nhận đúng ba giá trị, nên nó chờ đủ cả ba rồi mới kết thúc.
Interface không cần "implements"
Một kiểu thỏa mãn interface chỉ cần có đúng các phương thức. Không có từ khóa implements:
Rect và Circle không hề nhắc đến Shape, vậy mà cả hai đều cất được vào một []Shape. Nhờ đó bạn có thể định nghĩa interface ngay trong package dùng nó, dù các kiểu cụ thể đã được viết từ lâu.
Một bộ công cụ duy nhất
Lệnh go làm mọi thứ: go run biên dịch rồi chạy, go build tạo tệp nhị phân, go test chạy test, go fmt định dạng code, go vet bắt các cấu trúc đáng ngờ, và go mod quản lý phụ thuộc. Chỉ có một phong cách định dạng chính thức, do gofmt áp dụng, nên các dự án Go không phải tranh cãi chuyện dấu ngoặc nhọn hay thụt lề.
Những gì Go cố ý bỏ ra ngoài
Một số tính năng quen thuộc ở ngôn ngữ khác bị lược bỏ có chủ đích:
- Không có lớp hay kế thừa. Bạn dùng struct, phương thức, interface và embedding.
- Không có ngoại lệ. Lỗi là giá trị được trả về.
paniccó tồn tại, nhưng dành cho bug, không phải cho các thất bại thông thường. - Không có toán tử ba ngôi. Bạn viết
if/else. - Không có từ khóa
while.forlo mọi kiểu vòng lặp. - Không có nạp chồng hàm hay đối số mặc định.
- Generics chỉ có từ Go 1.18, và được giới hạn có chủ đích so với template của C++ hay generics của Java.
Ưu nhược điểm thật sự
Dài dòng. Kiểm tra lỗi tường minh và thiếu các cách viết tắt như toán tử ba ngôi khiến code Go dài hơn code Python hay Kotlin tương đương. Đọc thì dễ; viết thì tốn nhiều dòng hơn.
Bộ thu gom rác. Bộ thu gom rác của Go có thời gian dừng thấp, nhưng nó vẫn là bộ thu gom rác. Với hệ thống thời gian thực cứng hoặc code mà từng lần cấp phát bộ nhớ đều quan trọng, C, C++ hay Rust cho bạn nhiều quyền kiểm soát hơn.
Giá trị nil. Go có con trỏ, map, slice và interface nil. Truy cập qua con trỏ nil là một panic lúc chạy, và trình biên dịch không ngăn được điều đó như hệ thống kiểu của Rust.
Hệ thống kiểu nhỏ. Không có sum type, không có enum (bạn tự dựng bằng hằng số và iota), và generics chỉ phủ các trường hợp thông dụng chứ không đủ cho lập trình nâng cao ở mức kiểu.
Hệ sinh thái còn thiếu. Thư viện cho dịch vụ web, cơ sở dữ liệu và API cloud rất tốt. Với giao diện đồ họa, tính toán khoa học và học máy, Python, C++ hay Julia có nhiều hơn hẳn.
So sánh Go với các ngôn ngữ khác
| Go | Python | Java | Rust | |
|---|---|---|---|---|
| Kiểu | Tĩnh | Động | Tĩnh | Tĩnh |
| Chạy dưới dạng | Tệp nhị phân gốc | Trình thông dịch | Bytecode JVM | Tệp nhị phân gốc |
| Bộ nhớ | Thu gom rác | Thu gom rác | Thu gom rác | Ownership, không GC |
| Đồng thời | Goroutine, channel | Thread, asyncio (GIL giới hạn song song CPU) | Thread, virtual thread | Thread, async |
| Độ khó khi học | Thấp | Thấp | Trung bình | Cao |
Hãy chọn Go khi bạn muốn hiệu năng của ngôn ngữ biên dịch và triển khai đơn giản, mà không phải trèo đường cong học tập của Rust hay chịu sự rườm rà của Java.
Có nên học Go không?
Nếu bạn viết dịch vụ backend, công cụ dòng lệnh hay bất cứ thứ gì trong mảng hạ tầng cloud thì có. Phần lớn hệ sinh thái đó được viết bằng Go, và đọc mã nguồn của chúng là một phần công việc. Ngôn ngữ nhỏ nên công sức bỏ ra không nhiều: cú pháp cốt lõi mất vài ngày, còn lập trình đồng thời và xử lý lỗi theo đúng phong cách Go cần vài tuần luyện tập.
Để bắt đầu viết Go trên máy của bạn, hãy cài đặt Go, rồi đọc trang hello world, nơi giải thích từng dòng của chương trình đầu tiên.
Câu hỏi thường gặp
Golang dùng để làm gì?
Chủ yếu là phần mềm backend và hạ tầng: máy chủ web và API, microservice, công cụ dòng lệnh, code mạng và công cụ cho cloud. Docker, Kubernetes, Terraform và Prometheus đều viết bằng Go. Go hiếm khi được dùng cho ứng dụng desktop có giao diện, ứng dụng di động hay khoa học dữ liệu.
Go và Golang có phải là một không?
Đúng vậy. Tên của ngôn ngữ là Go. "Golang" xuất phát từ địa chỉ trang web đầu tiên, golang.org, và được dùng mãi vì "go" là một từ rất khó tìm kiếm. Cả hai tên đều chỉ cùng một ngôn ngữ và cùng một bộ công cụ.
Ai tạo ra ngôn ngữ lập trình Go?
Robert Griesemer, Rob Pike và Ken Thompson bắt đầu thiết kế Go tại Google từ năm 2007. Go được công bố mã nguồn mở vào tháng 11 năm 2009, và Go 1.0, phiên bản mở đầu cam kết tương thích của Go, ra mắt vào tháng 3 năm 2012.
Go có dễ học không?
Bản thân ngôn ngữ rất nhỏ: 25 từ khóa, một kiểu vòng lặp và một bản đặc tả ngắn bạn đọc hết trong một buổi chiều. Phần lớn lập trình viên đã biết một ngôn ngữ khác có thể viết Go chạy được chỉ sau vài ngày. Phần mất nhiều thời gian hơn là các cách viết đặc trưng: xử lý lỗi tường minh, interface, và viết code đồng thời đúng đắn với goroutine và channel.
Go là ngôn ngữ biên dịch hay thông dịch?
Biên dịch. go build tạo ra một tệp nhị phân mã máy gốc, không cần trình thông dịch hay máy ảo nào. go run cũng biên dịch; nó chỉ build ra một chỗ tạm rồi chạy kết quả.