Trong ngôn ngữ lập trình Go, chúng ta sử dụng thuật ngữ constant
để miêu tả các gía trị không đổi như là 5
, 1.34
, true
, "Hello"
. Những giá trị không đổi này còn được gọi là literals
Hằng số có thể là bất kỳ kiểu dữ liệu cơ bản nào như là hằng số integer, hằng số floating hay một string literal. Ngoài ra còn có hằng số enumeration.
Các hằng số được xử lý như một biến bình thường ngoại trừ việc giá trị của nó sẽ không thể chỉnh sửa sau khi định nghĩa.
Hằng số | Ví dụ |
Hằng số integer | 1000 , 67413 |
Hằng số floating | 4.56 , 128.372 |
Hằng số boolean | true , false |
Hằng số rune | 'C' , 'ä' |
Hằng số complex | 2.7i , 3 + 5i |
Hằng số string | "Hello" , "Rajeev" |
Khai báo một hằng số
Literals là một hằng số mà không cần tên. Để khai báo hằng số và đặt tên cho nó, chúng ta có thể sử dụng từ khoá const
như sau
const myFavLanguage = "Python" const sunRisesInTheEast = true
Chúng ta cũng có thể chỉ định kiểu như
const a int = 1234 const b string = "Hi"
Chúng ta cũng có thể khai báo nhiều hằng số trong một câu lệnh
const country, code = "Vietnam", 84 const ( employeeId string = "E101" salary float64 = 50000.0 )
Các hằng số, như chúng ta mong muốn, không thể bị thay đổi. Nghĩa là, không thể gán lại hằng số cho một giá trị khác sau khi nó đã được khởi tạo
const a = 123 a = 321 // Biên dịch lỗi (không thể gán lại hằng số)
Hằng số không gán kiểu
Bất kỳ hằng số nào trong Golang, được đặt tên hoặc không đặt tên, đều có thể không cần gán kiểu trừ khi định nghĩa cho nó một kiểu rõ ràng. Hãy cùng xem ví dụ sau đây, tất cả các hằng số đều không gán kiểu
1 // hằng số integer không gán kiểu 4.5 // hằng số floating không gán kiểu true // hằng số boolean không gán kiểu "Hello" // hằng số string không gán kiểu
Chúng không được gán kiểu cho dù chúng ta có đặt tên cho nó
const a = 1 const f = 4.5 const b = true const s = "Hello"
Giá trị 1
là một integer
, 4.5
là một float
, và "hello"
là một string
. Nhưng chúng chỉ là các giá trị và chưa được gán một kiểu cố định, như là int32
hoặc float64
hoặc string
, điều đó sẽ bắt buộc chúng phải tuân theo quy tắc kiểu nghiêm ngặt trong Go.
Thực tế rằng giá trị 1 không được gán kiểu cho phép chúng ta gán nó cho bất kỳ biến nào mà có kiểu tương thích với integer.
var myInt int = 1 var myFloat float64 = 1 var myComplex complex64 = 1
Mặc dù giá trị 1 không được gán kiểu, nó là một integer không gán kiểu. Nên nó chỉ có thể được sử dụng ở nơi integer được cho phép. Bạn không thể gán nó cho một biến string hoặc boolean.
Tương tự như vậy, hằng số floating không gán kiểu như là 4.5
có thể sử dụng bất kỳ chỗ nào kiểu floating cho phép
var myFloat32 float32 = 4.5 var myComplex64 complex64 = 4.5
Trong Golang, chúng ta có thể tạo một bí danh kiểu bằng cách sử dụng từ khoá type
như sau
type RichString string // Bí danh kiểu của `string`
Do đặc tính được định kiểu mạnh mẽ trong Go, bạn sẽ không thể gán một biến string cho biến RichString
var myString string = "Hello" var myRichString RichString = myString // không chạy.
Nhưng chúng ta có thể gán hằng số string không được gán kiểu cho biến RichString
bởi vì nó tương thích với string
const myUntypedString = "Hello" var myRichString RichString = myUntypedString // Chạy!
Hằng số và suy luận kiểu: Giá trị mặc định
Go hỗ trợ suy luận kiểu. Nó có thể suy luận ra kiểu của một biến từ giá trị mà nó được khởi tạo. Nên bạn có thể khai báo một biến với một giá trị khởi tạo mà không cần thông tin về kiểu, và Go sẽ tự động xác định kiểu cho nó
var a = 5 // Trình biên dịch Go tự động suy luận ra kiểu của biến `a`
Bạn có thể tìm hiểu rõ hơn trong bài viết trước về kiểu dữ liệu trong Golang.
Hằng số được gán kiểu
Trong Golang, hằng số được định kiểu khi chúng ta chỉ định kiểu rõ ràng trong khai báo như sau
const typedInt int = 1 // Hằng số được định kiểu
Cũng giống như các biến, tất cả các quy tắc của hệ thống kiểu trong Go áp dụng cho hằng số được gán kiểu. Ví dụ, bạn không thể gán kiểu hằng số integer cho biến float
var myFloat64 float64 = typedInt // Biên dịch lỗi
Với các hằng số được định kiểu, bạn sẽ mất đi tính linh động so với hằng số không được định kiểu như là gán chúng cho biến bất kỳ với kiểu tương thích hoặc pha trộn chúng với các toán tử toán học. Nên bạn chỉ khai báo kiểu cho hằng số nếu nó thực sự cần thiết. Ngoài ra chỉ nên khai báo hằng số không gán kiểu.
Các biểu thức
Một thực tế rằng, hằng số không gán kiểu cho phép chúng ta có thể pha trộn chúng bằng các biểu thức một cách thoải mái.
Nên bạn có thể có một biểu thức hằng số có thể chứa hỗn hợp các hằng số không gán kiểu khác nhau miễn là những hằng số này là tương thích với nhau.
const a = 5 + 7.5 // Hợp lệ const b = 12/5 // Hợp lệ const c = 'z' + 1 // Hợp lệ const d = "Hey" + true // Không hợp lệ (string và boolean không tương thích)
Tính toán của biểu thức và kết quả của nó tuân theo quy tắc nhất định.
1. Toán tử so sánh giữa 2 hằng số không gán kiểu luôn trả về một kiểu hằng số boolean.
const a = 7.5 > 5 // true const b = "xyz" < "uvw" // false
2. Đối với các toán tử khác (ngoại trừ shift)
- Nếu cả 2 toán hạng là cùng kiểu, kết quả trả về là cùng kiểu. Ví dụ biểu thức
25 / 2
thì kết quả trả về là 12 chứ không phải 12.5. Vì cả hai toán hạng đều là integer, nên kết quả được cắt ngắn thành số nguyên. - Nếu các toán hạng là khác kiểu, kết quả của kiểu toán hạng theo một quy tắc rộng hơn
integer < rune < floating-point < complex
const a = 25/2 // 12 (integer) const b = (6+8i)/2 // (3+4i) (complex)
- Toán tử shift hơi phức tạp một chút. Trước hết, có một số yêu cầu
- Toán hạng bên phải của biểu thức shift phải có một kiểu integer không dấu hoặc một hằng số không gán kiểu, có thể biểu thị giá trị kiểu
uint
- Toán hạng bên trải phải có một kiểu integer hoặc là một hằng số không gán kiểu, có thể biểu thị giá trị kiểu
int
- Toán hạng bên phải của biểu thức shift phải có một kiểu integer không dấu hoặc một hằng số không gán kiểu, có thể biểu thị giá trị kiểu
Nếu toán tử bên trái của biểu thức shift là hằng số không gán kiểu, kết qủa sẽ là một hằng số integer không gán kiểu. Trường hợp còn lại kết quả sẽ cùng kiểu với toán hạng bên trái.
const a = 1 << 5 // 32 (integer) const b = int32(1) << 4 // 16 (int32) const c = 16.0 >> 2 // 4 (integer) - 16.0 có thể biểu diễn giá trị kiểu `int` const d = 32 >> 3.0 // 4 (integer) - 3.0 có thể biểu diễn giá trị kiểu `uint` const e = 10.50 << 2 // trái luật (10.50 không thể biểu diễn giá trị kiểu `int`) const f = 64 >> -2 // trái luật (toán hạng bên phải là một int không dấu hoặc hằng số không gán kiểu tương thích với `uint`)
Ví dụ về biểu thức hằng số
Hãy cùng xem ví dụ về biểu thức hằng số sau
package main import "fmt" func main() { var result = 25/2 fmt.Printf("result is %v which is of type %T\n", result, result) }
Kết quả
result is 12 which is of type int
Vì cả 25 và 2 đều là int nên kết quả trả về cắt ngắn là 12
Để nhận được kết quả chính xác, chúng ta cần làm như sau
// sử dụng một giá trị float cho tử số hoặc mẫu số var result = 25.0/2
// Hoặc rõ ràng cho tử số hoặc mẫu số var result = float64(25)/2
Hãy cùng xem một ví dụ khác
package main import "fmt" func main() { var result = 4.5 + (10 - 5) * (3 + 2)/2 fmt.Println(result) }
Kết quả sẽ là gì? Nó không phải là 17.
Kết quả thực tế của nó sẽ là 16.5. Hãy cùng lướt qua từng phần tính toán để hiểu tại sao kết quả là 16.5
4.5 + (10 - 5) * (3 + 2)/2 ↓ 4.5 + (5) * (3 + 2)/2 ↓ 4.5 + (5) * (5)/2 ↓ 4.5 + (25)/2 ↓ 4.5 + 12 ↓ 16.5
Kết quả bị sai bởi vì 25 / 2
được làm tròn thành 12.
Để nhận được kết quả chính xác, bạn cần chỉnh sửa như sau
// sử dụng float giá trị cho tử số hoặc mẫu số var result = 4.5 + (10 - 5) * (3 + 2)/2.0
// Định kiểu rõ ràng cho tử số hoặc mẫu số var result = 4.5 + float64((10 - 5) * (3 + 2))/2