Packages
Mọi chương trình Go đều được tạo nên từ các package (đơn vị tổ chức mã nguồn).
Chương trình luôn bắt đầu chạy ở package main.
Chương trình dưới đây dùng hai package có import path (đường dẫn để import) là "fmt" và "math/rand".
Theo quy ước, tên package trùng với phần cuối cùng của import path. Ví dụ, package "math/rand" gồm các tệp bắt đầu bằng câu lệnh package rand.
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("My favorite number is", rand.Intn(10))
}
Chạy thử ví dụ này trong Tour of Go ↗
Imports
Đoạn mã này gom các lệnh import vào chung một cặp ngoặc đơn, gọi là import “gộp” (factored).
Bạn cũng có thể viết nhiều câu lệnh import riêng lẻ, như:
import "fmt"
import "math"
Nhưng cách viết gộp mới là cách viết đẹp, nên dùng.
package main
import (
"fmt"
"math"
)
func main() {
fmt.Printf("Now you have %g problems.\n", math.Sqrt(7))
}
Chạy thử ví dụ này trong Tour of Go ↗
Exported names
Trong Go, một cái tên là exported name (tên viết hoa chữ đầu, package khác dùng được) nếu nó bắt đầu bằng chữ in hoa. Ví dụ, Pizza là một exported name; Pi cũng vậy, nó được export từ package math.
pizza và pi không bắt đầu bằng chữ in hoa, nên chúng không được export.
Khi import một package, bạn chỉ dùng được các exported name của nó. Mọi cái tên “không export” đều không truy cập được từ bên ngoài package.
Hãy chạy thử đoạn mã. Để ý thông báo lỗi.
Để sửa lỗi, đổi math.pi thành math.Pi rồi chạy lại.
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println(math.pi)
}
Chạy thử ví dụ này trong Tour of Go ↗
Hàm
Một hàm có thể nhận không hoặc nhiều đối số.
Trong ví dụ này, add nhận hai tham số kiểu int.
Để ý rằng kiểu dữ liệu đứng sau tên biến.
(Muốn biết vì sao cú pháp khai báo lại trông như vậy, xem bài viết về cú pháp khai báo của Go.)
package main
import "fmt"
func add(x int, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
Chạy thử ví dụ này trong Tour of Go ↗
Hàm (tiếp)
Khi hai hay nhiều tham số liền nhau có cùng kiểu, bạn được phép bỏ bớt kiểu ở tất cả, chỉ giữ lại ở tham số cuối.
Trong ví dụ này, chúng tôi rút gọn
x int, y int
thành
x, y int
package main
import "fmt"
func add(x, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
Chạy thử ví dụ này trong Tour of Go ↗
Nhiều giá trị trả về
Một hàm có thể trả về bao nhiêu giá trị cũng được.
Hàm swap ở đây trả về hai chuỗi.
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
Chạy thử ví dụ này trong Tour of Go ↗
Đặt tên cho giá trị trả về
Giá trị trả về trong Go có thể được đặt tên. Khi đó chúng được xem như các biến khai báo ở đầu hàm.
Nên dùng những cái tên này để nói rõ ý nghĩa của từng giá trị trả về.
Câu lệnh return không kèm gì phía sau sẽ trả về đúng các giá trị đã đặt tên. Kiểu này gọi là “naked” return (return trần).
Chỉ nên dùng “naked” return trong hàm ngắn, như ví dụ ở đây. Trong hàm dài, nó làm mã khó đọc.
package main
import "fmt"
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
func main() {
fmt.Println(split(17))
}
Chạy thử ví dụ này trong Tour of Go ↗
Biến
Câu lệnh var khai báo một danh sách biến; giống như danh sách tham số của hàm, kiểu dữ liệu đứng sau cùng.
Câu lệnh var có thể nằm ở cấp package hoặc cấp hàm. Ví dụ này có cả hai.
package main
import "fmt"
var c, python, java bool
func main() {
var i int
fmt.Println(i, c, python, java)
}
Chạy thử ví dụ này trong Tour of Go ↗
Biến kèm giá trị khởi tạo
Một khai báo var có thể kèm giá trị khởi tạo, mỗi biến một giá trị.
Nếu đã có giá trị khởi tạo thì được phép bỏ kiểu đi; biến sẽ lấy luôn kiểu của giá trị đó.
package main
import "fmt"
var i, j int = 1, 2
func main() {
var c, python, java = true, false, "no!"
fmt.Println(i, j, c, python, java)
}
Chạy thử ví dụ này trong Tour of Go ↗
Khai báo biến rút gọn
Bên trong một hàm, bạn có thể dùng câu lệnh gán rút gọn := thay cho khai báo var mà không cần ghi kiểu.
Bên ngoài hàm, mọi câu lệnh đều phải bắt đầu bằng một từ khoá (var, func, v.v.) nên không dùng được := ở đó.
package main
import "fmt"
func main() {
var i, j int = 1, 2
k := 3
c, python, java := true, false, "no!"
fmt.Println(i, j, k, c, python, java)
}
Chạy thử ví dụ này trong Tour of Go ↗
Các kiểu cơ bản
Các kiểu dữ liệu cơ bản của Go là
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32
// represents a Unicode code point
float32 float64
complex64 complex128
Ví dụ dưới đây khai báo các biến thuộc nhiều kiểu khác nhau, đồng thời cho thấy khai báo biến cũng có thể gom thành khối giống như các câu lệnh import.
Kiểu int, uint và uintptr thường rộng 32 bit trên hệ thống 32 bit, và 64 bit trên hệ thống 64 bit. Khi cần một giá trị số nguyên, bạn nên dùng int, trừ khi có lý do cụ thể để chọn kiểu số nguyên có kích thước xác định hoặc không dấu.
package main
import (
"fmt"
"math/cmplx"
)
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)
func main() {
fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe)
fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt)
fmt.Printf("Type: %T Value: %v\n", z, z)
}
Chạy thử ví dụ này trong Tour of Go ↗
Zero value
Biến được khai báo mà không cho giá trị ban đầu sẽ nhận zero_value (giá trị mặc định) của kiểu đó.
Zero value là:
0với các kiểu số,falsevới kiểu boolean, và""(chuỗi rỗng) với chuỗi.
package main
import "fmt"
func main() {
var i int
var f float64
var b bool
var s string
fmt.Printf("%v %v %v %q\n", i, f, b, s)
}
Chạy thử ví dụ này trong Tour of Go ↗
Type conversion
Biểu thức T(v) chuyển giá trị v sang kiểu T (ép kiểu).
Vài ví dụ ép kiểu số:
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
Hoặc viết gọn hơn:
i := 42
f := float64(i)
u := uint(f)
Khác với C, trong Go việc gán giữa hai giá trị khác kiểu bắt buộc phải ép kiểu tường minh. Thử bỏ lệnh ép kiểu float64 hoặc uint trong ví dụ và xem chuyện gì xảy ra.
package main
import (
"fmt"
"math"
)
func main() {
var x, y int = 3, 4
var f float64 = math.Sqrt(float64(x*x + y*y))
var z uint = uint(f)
fmt.Println(x, y, z)
}
Chạy thử ví dụ này trong Tour of Go ↗
Type inference
Khi khai báo một biến mà không ghi rõ kiểu (dùng cú pháp := hoặc cú pháp var=` biểu_thức), kiểu của biến được suy ra từ giá trị ở vế phải. Đó gọi là type inference (suy luận kiểu).
Nếu vế phải đã có kiểu rõ ràng, biến mới sẽ mang đúng kiểu đó:
var i int
j := i // j is an int
Nhưng nếu vế phải là một constant số chưa có kiểu, biến mới có thể là int, float64 hay complex128, tuỳ theo độ chính xác của constant đó:
i := 42 // int
f := 3.142 // float64
g := 0.867 + 0.5i // complex128
Thử đổi giá trị khởi tạo của v trong đoạn mã ví dụ và xem kiểu của nó thay đổi thế nào.
package main
import "fmt"
func main() {
v := 42 // change me!
fmt.Printf("v is of type %T\n", v)
}
Chạy thử ví dụ này trong Tour of Go ↗
Constant
Constant (hằng số) được khai báo giống như biến, nhưng dùng từ khoá const.
Constant có thể là ký tự, chuỗi, boolean hoặc giá trị số.
Không thể khai báo constant bằng cú pháp :=.
package main
import "fmt"
const Pi = 3.14
func main() {
const World = "世界"
fmt.Println("Hello", World)
fmt.Println("Happy", Pi, "Day")
const Truth = true
fmt.Println("Go rules?", Truth)
}
Chạy thử ví dụ này trong Tour of Go ↗
Constant số
Constant số là những giá_trị có độ chính xác rất cao.
Một constant chưa có kiểu sẽ nhận kiểu mà ngữ cảnh dùng nó đòi hỏi.
Thử in thêm needInt(Big) xem sao.
(Kiểu int chứa được tối đa một số nguyên 64 bit, đôi khi còn ít hơn.)
package main
import "fmt"
const (
// Create a huge number by shifting a 1 bit left 100 places.
// In other words, the binary number that is 1 followed by 100 zeroes.
Big = 1 << 100
// Shift it right again 99 places, so we end up with 1<<1, or 2.
Small = Big >> 99
)
func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
return x * 0.1
}
func main() {
fmt.Println(needInt(Small))
fmt.Println(needFloat(Small))
fmt.Println(needFloat(Big))
}
Chạy thử ví dụ này trong Tour of Go ↗
Chúc mừng!
Bạn đã hoàn thành bài học này!
Bạn có thể quay lại danh sách module để chọn nội dung học tiếp, hoặc đi thẳng tới bài học tiếp theo.