Skip to content

Hằng số trong Go

Giá trị của hằng số không thể thay đổi trong thời gian chạy, một khi đã gán giá trị thì không thể sửa đổi, giá trị của nó chỉ có thể đến từ:

  • Giá trị chữ
  • Định danh hằng số khác
  • Biểu thức hằng số
  • Chuyển đổi kiểu có kết quả là hằng số
  • iota

Hằng số chỉ có thể là kiểu dữ liệu cơ bản, không thể là

  • Các kiểu khác ngoài kiểu cơ bản như cấu trúc, interface, slice, mảng, v.v.
  • Giá trị trả về của hàm

Giá trị của hằng số không thể bị sửa đổi, nếu không sẽ không thể biên dịch

Khởi tạo

Khai báo hằng số cần dùng từ khóa const, hằng số khi khai báo phải khởi tạo một giá trị, và kiểu của hằng số có thể bỏ qua, ví dụ

go
const name string = "Jack" // Giá trị chữ

const msg = "hello world" // Giá trị chữ

const num = 1 // Giá trị chữ

const numExpression = (1+2+3) / 2 % 100 + num // Biểu thức hằng số

Nếu chỉ khai báo mà không chỉ định giá trị, sẽ không thể biên dịch

go
const name string

Trình biên dịch báo lỗi

missing init expr for name

Khai báo hàng loạt hằng số có thể dùng () để bao lại nhằm nâng cao khả năng đọc, có thể tồn tại nhiều () để đạt hiệu quả phân nhóm.

go
const (
   Count = 1
   Name  = "Jack"
)

const (
   Size = 16
   Len  = 25
)

Trong cùng một nhóm hằng số, các hằng số phía sau hằng số đã được gán giá trị có thể không cần gán giá trị, giá trị của nó mặc định là giá trị của hằng số trước đó, ví dụ

go
const (
  A = 1
  B // 1
  C // 1
  D // 1
  E // 1
)

iota

iota là một định danh hằng số tích hợp, thường được sử dụng để biểu thị số thứ tự số nguyên không kiểu trong một khai báo hằng số, thường được sử dụng trong ngoặc đơn.

go
const iota = 0

Xem một vài ví dụ sử dụng

go
const (
   Num = iota // 0
   Num1 // 1
   Num2 // 2
   Num3 // 3
   Num4 // 4
)

Cũng có thể viết như sau

go
const (
   Num = iota*2 // 0
   Num1 // 2
   Num2 // 4
   Num3 // 6
   Num4 // 8
)

Cũng có thể

go
const (
   Num = iota << 2*3 + 1 // 1
   Num1 // 13
   Num2 // 25
   Num3 = iota // 3
   Num4 // 4
)

Thông qua một vài ví dụ trên có thể phát hiện, iota là tăng dần, biểu thức giá trị iota của hằng số đầu tiên sử dụng iota, dựa trên sự thay đổi của giá trị số thứ tự sẽ tự động gán cho các hằng số tiếp theo, cho đến khi được đặt lại bằng const mới, số thứ tự này thực chất là số dòng mã tương đối, là số dòng tương đối so với dòng bắt đầu của nhóm hiện tại, xem ví dụ dưới đây

go
const (
  Num  = iota<<2*3 + 1 // 1 Dòng thứ nhất
  Num2 = iota<<2*3 + 1 // 13 Dòng thứ hai
  _ // 25 Dòng thứ ba
  Num3 //37 Dòng thứ tư
  Num4 = iota // 4 Dòng thứ năm
  _ // 5 Dòng thứ sáu
  Num5 // 6 Dòng thứ bảy
)

Trong ví dụ sử dụng định danh ẩn danh _ để chiếm một vị trí dòng, có thể thấy giá trị của iota về bản chất là hiệu số giữa dòng mà iota đang ở so với dòng đầu tiên của nhóm const hiện tại. Và các nhóm const khác nhau thì không ảnh hưởng lẫn nhau.

Enum

Ngôn ngữ Go không thiết kế riêng một kiểu dữ liệu cho enum, không giống như các ngôn ngữ khác thường có một enum để biểu thị. Thông thường trong Go, đều thông qua kiểu tùy chỉnh + const + iota để thực hiện enum, dưới đây là một ví dụ đơn giản

go
type Season uint8

const (
  Spring Season = iota
  Summer
  Autumn
  Winter
)

Các enum này thực chất là số, Go cũng không hỗ trợ chuyển đổi trực tiếp thành chuỗi, nhưng chúng ta có thể thêm phương thức cho kiểu tùy chỉnh để trả về biểu diễn chuỗi của nó, thực hiện interface Stringer là được.

go
func (s Season) String() string {
  switch s {
  case Spring:
    return "mùa xuân"
  case Summer:
    return "mùa hè"
  case Autumn:
    return "mùa thu"
  case Winter:
    return "mùa đông"
  }
  return ""
}

Như vậy là đã thực hiện một enum đơn giản. Bạn cũng có thể thông qua công cụ chính thức Stringer để tự động tạo enum.

Tuy nhiên nó có những nhược điểm sau:

  • Không an toàn kiểu, vì Season là kiểu tùy chỉnh, có thể thông qua chuyển đổi kiểu bắt buộc để chuyển đổi các số khác thành kiểu đó

    go
    Season(6)
  • Rườm rà, biểu diễn chuỗi cần tự mình thực hiện

  • Khả năng biểu đạt yếu, vì const chỉ hỗ trợ kiểu dữ liệu cơ bản, nên các giá trị enum này cũng chỉ có thể được biểu thị bằng chuỗi và số

Tại sao không hỗ trợ enum ở cấp độ ngôn ngữ là điều mà tác giả rất không thể hiểu được, tôi cho rằng điều này chắc chắn là lợi大于弊.

Golang by www.golangdev.cn edit