Menu

Golang là gì? Giới thiệu ngôn ngữ Go qua ví dụ

Go (thường gọi là Golang) là ngôn ngữ biên dịch, kiểu tĩnh do Google thiết kế để xây dựng máy chủ và công cụ nhanh, ổn định. Trang này giải thích Go là gì, dùng để làm gì và đâu là điểm yếu của nó.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

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ư net có thể liên kết với thư viện C của hệ thống, và CGO_ENABLED=0 sẽ 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ựcVí dụ
Web API và microserviceDịch vụ HTTP và gRPC, backend cho ứng dụng web và di động
Công cụ cloud và hạ tầngDocker, Kubernetes, Terraform, Prometheus
Công cụ dòng lệnhCLI 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ạngProxy, bộ cân bằng tải, máy chủ DNS
Pipeline dữ liệuWorker đọ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ề. panic có 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. for lo 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

GoPythonJavaRust
KiểuTĩnhĐộngTĩnhTĩnh
Chạy dưới dạngTệp nhị phân gốcTrình thông dịchBytecode JVMTệp nhị phân gốc
Bộ nhớThu gom rácThu gom rácThu gom rácOwnership, không GC
Đồng thờiGoroutine, channelThread, asyncio (GIL giới hạn song song CPU)Thread, virtual threadThread, async
Độ khó khi họcThấpThấpTrung bìnhCao

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ả.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu