Cú pháp cơ bản
Cú pháp cơ bản của Go rất đơn giản và dễ hiểu, hãy bắt đầu với một ví dụ đơn giản nhất.
package main
import "fmt"
func main() {
fmt.Println("Xin chào thế giới!")
}Từ khóa
packagekhai báo tệp go hiện tại thuộc về gói nào, tệp入口 phải được khai báo là góimain, hàm入口 là hàmmain, khi tùy chỉnh gói và hàm, nên tránh trùng tên với chúng.importlà từ khóa để nhập, theo sau là tên gói được nhập.funclà từ khóa khai báo hàm, dùng để khai báo một hàm.fmt.Println("Xin chào thế giới!")là một câu lệnh, gọi hàmPrintlntrong góifmtđể xuất.
Trên đây là một giới thiệu cú pháp đơn giản, sau đây sẽ tìm hiểu chi tiết hơn về các khái niệm bên trong.
Gói
Trong Go, chương trình được xây dựng bằng cách liên kết các gói với nhau. Đơn vị cơ bản để nhập trong Go là một gói, chứ không phải tệp .go. Gói thực chất là một thư mục, tên tiếng Anh là package, gói chia sẻ tất cả các biến, hằng số và tất cả các loại được định nghĩa. Phong cách đặt tên gói nên là chữ thường và nên ngắn gọn.
Khả năng hiển thị
Như đã đề cập trước đó, gói chia sẻ tất cả các biến, hằng số và tất cả các loại được định nghĩa, nhưng đối với bên ngoài gói thì không phải vậy, đôi khi bạn không muốn người khác truy cập một loại nào đó, vì vậy cần kiểm soát khả năng hiển thị. Bạn có thể đã thấy các từ khóa như Public, Private trong các ngôn ngữ OOP khác, nhưng trong Go không có những từ khóa này, cách kiểm soát khả năng hiển thị của nó rất đơn giản, quy tắc như sau
- Tên bắt đầu bằng chữ cái viết hoa, tức là loại/biến/hằng số công khai
- Tên bắt đầu bằng chữ cái viết thường hoặc dấu gạch dưới, tức là loại/biến/hằng số riêng tư
Ví dụ như ví dụ dưới đây, hằng số MyName là công khai, còn hằng số mySalary là riêng tư.
package example
// Công khai
const MyName = "jack"
// Riêng tư
const mySalary = 20_000Quy tắc khả năng hiển thị này áp dụng cho mọi nơi trong toàn bộ ngôn ngữ Go.
Nhập
Nhập một gói để sử dụng các loại/phương thức/hàm/biến trong gói đó, cú pháp nhập là import cộng với tên gói
package main
import "example"Khi nhập nhiều gói, bạn có thể viết như sau
package main
import "example"
import "example1"Hoặc có thể dùng ngoặc đơn括起来, cách viết này thực tế được sử dụng phổ biến hơn.
package main
import (
"example"
"example1"
)Nếu có tên gói trùng lặp hoặc tên gói phức tạp, bạn cũng có thể đặt bí danh cho chúng
package main
import (
e "example"
e1 "example1"
)Khi bí danh là dấu gạch dưới _ thì đó là nhập ẩn danh, gói được nhập ẩn danh không thể được sử dụng, việc này thường được thực hiện để tải hàm init trong gói, nhưng không cần sử dụng các loại trong gói, một ví dụ phổ biến là đăng ký driver cơ sở dữ liệu, nhưng bạn không cần phải sử dụng driver thủ công.
package main
import (
e "example"
_ "mysql-driver-go"
)Sau khi nhập, khi muốn truy cập các loại trong gói, bạn có thể truy cập thông qua tên_gói.định_danh, như trong ví dụ dưới đây, nếu bạn cố truy cập một loại riêng tư, trình biên dịch sẽ cho bạn biết không thể truy cập.
package main
import (
"example"
"fmt"
)
func main() {
fmt.Println(example.MyName)
}Có một cách nhập đặc biệt là nhập tất cả các loại trong gói vào phạm vi gói hiện tại, với cách nhập này, các loại không cần toán tử . để truy cập nữa, nhưng nếu có loại trùng tên sẽ không thể biên dịch được.
package main
import (
. "example"
)WARNING

Trong Go không thể nhập vòng lặp, dù là trực tiếp hay gián tiếp. Ví dụ, gói A nhập gói B, gói B cũng nhập gói A, đây là nhập vòng lặp trực tiếp, gói A nhập gói C, gói C nhập gói B, gói B lại nhập gói A, đây là nhập vòng lặp gián tiếp, nếu có nhập vòng lặp sẽ không thể biên dịch được.
Gói nội bộ
Trong Go, quy ước rằng một gói có tên là internal trong một gói là gói nội bộ, gói bên ngoài sẽ không thể truy cập bất kỳ nội dung nào trong gói nội bộ, nếu không thì biên dịch sẽ không thành công, xem một ví dụ dưới đây.
/home/user/go/
src/
crash/
bang/ (mã go trong package bang)
b.go
foo/ (mã go trong package foo)
f.go
bar/ (mã go trong package bar)
x.go
internal/
baz/ (mã go trong package baz)
z.go
quux/ (mã go trong package main)
y.goTừ cấu trúc tệp có thể thấy, gói crash không thể truy cập các loại trong gói baz.
Chú thích
Go hỗ trợ chú thích một dòng và chú thích nhiều dòng, nên cách một khoảng trắng giữa chú thích và nội dung, ví dụ
// Đây là gói main
package main
// Đã nhập gói fmt
import "fmt"
/*
*
Đây là hàm khởi động hàm main
*/
func main() {
// Đây là một câu lệnh
fmt.Println("Xin chào thế giới!")
}Định danh
Định danh là một tên, dùng để đặt tên gói, đặt tên hàm, đặt tên biến, v.v., quy tắc đặt tên như sau
- Chỉ có thể bao gồm chữ cái, số, dấu gạch dưới
- Chỉ có thể bắt đầu bằng chữ cái và dấu gạch dưới
- Phân biệt chữ hoa chữ thường nghiêm ngặt
- Không được trùng với bất kỳ định danh nào đã tồn tại, tức là duy nhất trong gói
- Không được xung đột với bất kỳ từ khóa tích hợp nào của Go
Dưới đây liệt kê tất cả các từ khóa tích hợp, bạn cũng có thể đến Sổ tay tham khảo - Định danh để xem thêm chi tiết
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return varToán tử
Dưới đây là thứ tự ưu tiên của các toán tử được hỗ trợ trong ngôn ngữ Go, bạn cũng có thể đến Sổ tay tham khảo - Toán tử để xem thêm chi tiết.
Precedence Operator
5 * / % << >> & &^
4 + - | ^
3 == != < <= > >=
2 &&
1 ||Có một điểm cần lưu ý, trong ngôn ngữ Go không chọn ~ làm toán tử phủ định, mà tái sử dụng ký hiệu ^, khi hai số sử dụng ^, ví dụ a^b, nó là toán tử XOR, chỉ khi sử dụng với một số, ví dụ ^a, thì nó là toán tử phủ định. Go cũng hỗ trợ toán tử gán tăng cường, như sau.
a += 1
a /= 2
a &^= 2TIP
Ngôn ngữ Go không có toán tử tự tăng và tự giảm, chúng được hạ cấp thành câu lệnh statement, và quy định chỉ có thể đứng sau toán hạng, vì vậy không cần phải băn khoăn về vấn đề i++ và ++i.
a++ // Đúng
++a // Sai
a-- // ĐúngMột điểm nữa là chúng không còn có giá trị trả về, vì vậy các câu lệnh như a = b++ là sai.
Giá trị chữ
Giá trị chữ, theo thuật ngữ khoa học máy tính là ký hiệu dùng để biểu thị một giá trị cố định trong mã nguồn, còn gọi là giá trị chữ. Hai cách gọi này đều có cùng ý nghĩa, viết cái gì thì giá trị là cái đó, giá trị là giá trị "theo nghĩa đen".
Giá trị chữ số nguyên
Để dễ đọc, cho phép sử dụng dấu gạch dưới _ để phân chia số, nhưng chỉ được phép sử dụng sau ký hiệu tiền tố và giữa các chữ số.
24 // 24
024 // 24
2_4 // 24
0_2_4 // 24
10_000 // 10k
100_000 // 100k
0O24 // 20
0b00 // 0
0x00 // 0
0x0_0 // 0Giá trị chữ số dấu phẩy động
Thông qua các tiền tố khác nhau có thể biểu thị số dấu phẩy động của các hệ cơ số khác nhau
0.
72.40
072.40 // == 72.40
2.71828
1.e+0
6.67428e-11
1E6
.25
.12345E+5
1_5. // == 15.0
0.15e+0_2 // == 15.0
0x1p-2 // == 0.25
0x2.p10 // == 2048.0
0x1.Fp+0 // == 1.9375
0X.8p-0 // == 0.5
0X_1FFFP-16 // == 0.1249847412109375
0x15e-2 // == 0x15e - 2 (phép trừ số nguyên)Giá trị chữ số phức
0i
0123i // == 123i
0o123i // == 0o123 * 1i == 83i
0xabci // == 0xabc * 1i == 2748i
0.i
2.71828i
1.e+0i
6.67428e-11i
1E6i
.25i
.12345E+5i
0x1p-2i // == 0x1p-2 * 1i == 0.25iGiá trị chữ ký tự
Giá trị chữ ký tự phải được括 trong dấu nháy đơn '', ký tự trong Go hoàn toàn tương thích với utf8.
'a'
'ä'
'你'
'\t'
'\000'
'\007'
'\377'
'\x07'
'\xff'
'\u12e4'
'\U00101234'Ký tự thoát
Các ký tự thoát có sẵn trong Go
\a U+0007 Ký hiệu chuông
\b U+0008 Ký hiệu lùi
\f U+000C Ký hiệu chuyển trang
\n U+000A Ký hiệu xuống dòng
\r U+000D Ký hiệu quay lại
\t U+0009 Ký hiệu tab ngang
\v U+000B Ký hiệu tab dọc
\\ U+005C Ký hiệu thoát dấu gạch chéo ngược
\' U+0027 Ký hiệu thoát dấu nháy đơn (chỉ có hiệu lực trong ký tự)
\" U+0022 Ký hiệu thoát dấu nháy kép (chỉ có hiệu lực trong chuỗi)Giá trị chữ chuỗi
Giá trị chữ chuỗi phải được括 trong dấu nháy kép "" hoặc dấu nháy ngược `` (chuỗi dấu nháy ngược không cho phép thoát)
`abc` // "abc"
`\n
\n` // "\\n\n\\n"
"\n"
"\"" // `"`
"Hello, world!\n"
"Hôm nay thời tiết đẹp"
"日本語"
"\u65e5本\U00008a9e"
"\xff\u00FF"Hàm
Cách khai báo hàm trong Go được thực hiện thông qua từ khóa func, tương tự như hầu hết các ngôn ngữ
func main() {
println(1)
}Tuy nhiên, có hai điểm khác biệt trong hàm của Go, điểm đầu tiên là kiểu tham số đứng sau, như dưới đây
func Hello(name string) {
fmt.Println(name)
}Điểm khác biệt thứ hai là nhiều giá trị trả về, và có thể có tên
func Pos() () (x, y float64) {
...
}Phong cách
Về phần phong cách mã hóa, Go bắt buộc tất cả mọi người thống nhất cùng một phong cách, Go chính thức cung cấp một công cụ định dạng gofmt, có thể sử dụng thông qua dòng lệnh, công cụ định dạng này không có bất kỳ tham số định dạng nào để truyền, chỉ có hai tham số duy nhất cũng chỉ là xuất quá trình định dạng, vì vậy hoàn toàn không hỗ trợ tùy chỉnh, nghĩa là tất cả mã sau khi định dạng bằng công cụ này đều có cùng một phong cách mã, điều này sẽ giảm đáng kể gánh nặng tinh thần cho người bảo trì, vì vậy việc theo đuổi cá tính trong phần này rõ ràng không phải là lựa chọn khôn ngoan.
Dưới đây sẽ liệt kê đơn giản một số quy tắc,平时 khi viết mã cũng có thể lưu ý một chút.
Dấu ngoặc nhọn hàm xuống dòng
Về việc dấu ngoặc nhọn sau hàm có nên xuống dòng hay không, hầu như mỗi lập trình viên đều có thể đưa ra lý do của riêng mình, trong Go tất cả các dấu ngoặc nhọn không nên xuống dòng
// Ví dụ đúng
func main() {
fmt.Println("Xin chào thế giới!")
}Nếu bạn thực sự làm như vậy, như dưới đây
// Ví dụ sai
func main()
{
fmt.Println("Xin chào thế giới!")
}Mã như vậy thậm chí không thể biên dịch được, vì vậy Go bắt buộc tất cả các lập trình viên không xuống dòng dấu ngoặc sau hàm.
Thụt lề mã
Go mặc định sử dụng Tab tức là ký tự tab để thụt lề, chỉ trong một số trường hợp đặc biệt sẽ sử dụng dấu cách.
Khoảng cách mã
Hầu hết các khoảng cách trong Go đều có ý nghĩa, ở một mức độ nào đó, điều này cũng đại diện cho cách trình biên dịch xem mã của bạn, ví dụ như phép toán toán học dưới đây
2*9 + 1/3*2Như chúng ta đã biết, ưu tiên của phép nhân cao hơn phép cộng, sau khi định dạng, khoảng cách giữa các ký hiệu * sẽ chặt chẽ hơn, có nghĩa là ưu tiên thực hiện phép tính, còn khoảng cách gần ký hiệu + thì lớn hơn, đại diện cho việc thực hiện sau.
Bỏ qua dấu ngoặc nhọn
Trong các ngôn ngữ khác, câu lệnh if và for thường có thể được viết tắt, như dưới đây
for (int i=0; i < 10; i++) printf("%d", i)Nhưng trong Go thì không, bạn có thể chỉ viết một dòng, nhưng phải thêm dấu ngoặc nhọn
for i := 0; i < 10; i++ {fmt.Println(i)}Biểu thức tam nguyên
Go không có biểu thức tam nguyên, vì vậy mã như dưới đây không thể biên dịch được
var c = a > b ? a : bThông qua bài viết này, bạn có thể có nhận thức sơ bộ về cú pháp Go, các nội dung tiếp theo sẽ được triển khai chi tiết hơn.
