1. Biến và Hằng số

Trong Golang, biến và hằng số là hai khái niệm cơ bản có vai trò rất quan trọng trong một chương trình.

  • Một biến là một bí danh được sử dụng để lưu trữ dữ liệu trong một chương trình. Trong Golang, từ khóa var được sử dụng để khai báo biến.
  • Một hằng số là một bí danh mà giá trị không thể thay đổi trong chương trình. Trong Golang, từ khóa const được sử dụng để khai báo hằng số.

2 Khai báo và Khởi tạo biến trong Golang

2.1 Khai báo và Gán giá trị cho Một Biến Đơn

Trong ngôn ngữ Go, từ khóa var được sử dụng để khai báo biến theo định dạng var tên_biến kiểu_dữ_liệu. Sau khi khai báo, biến có thể được gán giá trị trong code tiếp theo, hoặc có thể được khởi tạo trực tiếp tại thời điểm khai báo. Ví dụ:

var age int // Khai báo một biến kiểu số nguyên là age
age = 25    // Gán giá trị cho biến

var name string = "Alice" // Khai báo và khởi tạo biến name

2.2 Khai báo nhiều Biến cùng lúc

Ngôn ngữ Golang hỗ trợ khai báo đồng thời nhiều biến, điều này giúp làm cho code trở nên ngắn gọn hơn. Thông thường, việc khai báo nhiều biến được thực hiện ở đầu của một hàm hoặc tại cấp độ package. Ví dụ:

var (
    firstName, lastName string
    age                 int
)

firstName = "John"
lastName = "Doe"
age = 30

Trong khai báo đồng loạt ở trên, firstNamelastName được khai báo là chuỗi, trong khi age là một số nguyên.

2.3 Suy luận Kiểu và Khai báo biến ngắn gọn

Trong ngôn ngữ Go, không luôn cần phải chỉ định rõ kiểu của biến. Nếu có biểu thức khởi tạo được cung cấp khi khai báo biến, Go có thể suy luận được kiểu của biến. Điều này được gọi là suy luận kiểu. Khai báo biến ngắn gọn sử dụng := có thể làm cho câu lệnh khai báo và khởi tạo biến dựa trên suy luận kiểu trở nên đơn giản. Ví dụ:

city := "Beijing" // Sử dụng khai báo biến ngắn gọn để đồng thời khai báo và khởi tạo city
country := "China" // country được suy luận là kiểu chuỗi

Cần lưu ý rằng khai báo biến ngắn gọn chỉ có thể được sử dụng trong các hàm và không thể được sử dụng ở phạm vi toàn cục.

2.4 Khai báo biến ở bên ngoài các Hàm

Các biến được khai báo ở bên ngoài các hàm có phạm vi ở cấp độ package. Các biến này có thể nhìn thấy và truy cập trong toàn bộ package. Ví dụ:

var globalVar string = "I am global" // Khai báo một biến toàn cục

func printGlobalVar() {
    fmt.Println(globalVar) // Truy cập biến toàn cục trong hàm
}

Các biến toàn cục có thể được chia sẻ giữa bất kỳ hàm nào trong package, nhưng cần được sử dụng cẩn thận để tránh xung đột tên và tham chiếu không rõ ràng.

Mẹo: Ở đây chỉ cần hiểu mã chức năng cơ bản, giải thích chi tiết về chức năng sẽ được cung cấp trong các phần sau.

3. Các Kiểu Dữ Liệu Cơ Bản và Giá trị Zero

3.1 Các Kiểu Dữ Liệu Cơ Bản trong Golang

Trong ngôn ngữ Go, mỗi loại biến cung cấp ngữ nghĩa và đặc tính hành vi rõ ràng. Dưới đây là một số loại dữ liệu cơ bản phổ biến:

  • int, int8, int16, int32, int64: Các loại số nguyên có phạm vi khác nhau
  • uint, uint8, uint16, uint32, uint64: Số nguyên không dấu
  • float32, float64: Số dấu chấm động
  • bool: Giá trị logic (true hoặc false)
  • string: Chuỗi

3.2 Khái niệm Giá trị Zero

Trong ngôn ngữ Go, biến được tự động khởi tạo với giá trị zero của kiểu dữ liệu tương ứng sau khi được khai báo. Giá trị zero là giá trị mặc định của kiểu tương ứng khi một biến không được khởi tạo một cách rõ ràng. Điều này không phổ biến trong một số ngôn ngữ khác, nhưng trong Go, điều này đảm bảo rằng tất cả các biến luôn có một giá trị khởi tạo hợp lệ. Dưới đây là giá trị zero của mỗi kiểu dữ liệu cơ bản:

  • Giá trị zero cho một số nguyên là 0
  • Giá trị zero cho một số dấu chấm động là 0.0
  • Giá trị zero cho một giá trị logic là false
  • Giá trị zero cho một chuỗi là một chuỗi rỗng ""

Ví dụ:

var i int     // Giá trị zero là 0
var f float64 // Giá trị zero là 0.0
var b bool    // Giá trị zero là false
var s string  // Giá trị zero là ""

Hiểu rõ khái niệm giá trị zero rất quan trọng, vì nó có thể giúp nhà phát triển hiểu rõ hành vi của việc khởi tạo biến và có thể được sử dụng để ngăn ngừa lỗi con trỏ rỗng hoặc chưa khởi tạo.

4. Phạm vi của Biến

4.1 Biến Cục Bộ

Biến cục bộ là các biến được định nghĩa trong một hàm và chỉ có thể truy cập trong phạm vi của hàm đó. Các tham số hàm cũng thuộc về biến cục bộ. Từ lúc được tạo ra cho đến khi thực thi hàm hoàn thành, các biến cục bộ sẽ biến mất. Mỗi khi một hàm được gọi, các biến cục bộ lại được tạo mới.

func localVariableExample() {
    var localVariable int = 10 // Đây là một biến cục bộ
    fmt.Println(localVariable)
}

func main() {
    localVariableExample() // Output: 10
    // fmt.Println(localVariable) // Điều này sẽ gây lỗi biên dịch vì localVariable không có thể nhìn thấy ở đây
}

Trong ví dụ trên, localVariable chỉ có thể truy cập trong hàm localVariableExample.

4.2 Biến Toàn Cục

Biến toàn cục là các biến được định nghĩa bên ngoài các hàm, và chúng có thể được truy cập trong bất kỳ tệp nào trong cùng gói. Nếu bạn muốn sử dụng biến toàn cục trong các gói khác, tên biến phải bắt đầu bằng chữ cái in hoa, phù hợp với quy tắc kiểm soát truy cập của Go.

package main

import "fmt"

var globalVariable int = 20 // Đây là một biến toàn cục

func main() {
    fmt.Println(globalVariable) // Output: 20
    changeGlobal()
    fmt.Println(globalVariable) // Output: 30
}

func changeGlobal() {
    globalVariable = 30 // Thay đổi giá trị của biến toàn cục
}

Trong ví dụ này, globalVariable có thể thấy ở cả hàm main và hàm changeGlobal.

5 Khai Báo và Sử Dụng Hằng

5.1 Từ Khóa const

Chúng ta sử dụng từ khóa const để định nghĩa các hằng. Hằng số là các giá trị không thể được thay đổi và một khi được định nghĩa, giá trị của chúng không thể thay đổi. Hằng có thể là bất kỳ kiểu dữ liệu cơ bản nào như số nguyên, số thực, boolean hoặc chuỗi.

const Pi = 3.14 // Khai báo một hằng số số thực
const StrConst string = "Xin chào, thế giới!" // Khai báo một hằng số chuỗi

func main() {
    fmt.Println(Pi)
    fmt.Println(StrConst)
}

5.2 Hằng Enum

Ngôn ngữ Go không có một kiểu liệt kê cụ thể, nhưng bạn có thể sử dụng từ khóa iota để đạt được việc liệt kê. Trong một khối const, mỗi khai báo hằng số bổ sung sẽ tăng giá trị của iota lên 1.

const (
    Sunday = iota  // 0
    Monday         // 1
    Tuesday        // 2
    Wednesday      // 3
    Thursday       // 4
    Friday         // 5
    Saturday       // 6
)

func main() {
    fmt.Println(Sunday)    // Output: 0
    fmt.Println(Saturday)  // Output: 6
}

Đoạn code trên khai báo một liệt kê cho các ngày trong tuần, trong đó iota khởi tạo ở 0 trong khối const và tăng lên 1 cho mỗi khai báo sau đó.

5.3 Phạm Vi của Hằng

Phạm vi của hằng tương tự như biến. Nếu một hằng được định nghĩa trong một hàm, phạm vi của nó chỉ giới hạn trong hàm đó. Nếu một hằng được định nghĩa bên ngoài một hàm (toàn cục), phạm vi của nó là toàn bộ gói, và nếu chữ cái đầu tiên là in hoa, nó có thể được truy cập trong các gói khác.

Quản lý phạm vi của hằng giúp giảm ô nhiễm phạm vi toàn cục và cải thiện tính bảo trì và đọc hiểu của chương trình.

const GlobalConst = "Đây là hằng số toàn cầu"

func main() {
    const LocalConst = "Đây là hằng số cục bộ"
    fmt.Println(GlobalConst)  // Điều này hợp lệ
    fmt.Println(LocalConst)   // Điều này hợp lệ
}

func anotherFunction() {
    // fmt.Println(LocalConst) // Điều này sẽ gây lỗi biên dịch: LocalConst không thể nhìn thấy trong hàm này
    fmt.Println(GlobalConst)  // Điều này hợp lệ
}