[Golang cơ bản] Tìm hiểu về biến trong golang

Post on: 2023-03-27 00:05:58 | in: Golang
Trong Go, một biến là một vị trí trong bộ nhớ được dùng để lưu trữ một giá trị. Một biến được khai báo bằng từ khóa "var" và có thể có một kiểu dữ liệu được chỉ định hoặc không.

Tổng quan

Một biến là tên của một vị trí trong bộ nhớ. Vị trí đó có thể lưu trữ một giá trị của bất kỳ kiểu dữ liệu nào. Vì vậy, mỗi biến có một kiểu dữ liệu liên quan đến nó, xác định kích thước và phạm vi của biến đó cũng như các hoạt động được định nghĩa trên biến đó.

Các quy ước đặt tên

  • Một tên biến chỉ có thể bắt đầu bằng một chữ cái hoặc dấu gạch dưới.
  • Sau đó, nó có thể được theo sau bởi bất kỳ số lượng chữ cái, số hoặc dấu gạch dưới nào.
  • Go is case sensitive so uppercase and lowercase letters are treated differently.
  • Go là ngôn ngữ phân biệt chữ hoa chữ thường, vì vậy chữ hoa và chữ thường được coi là khác nhau trong tên biến.
  • Tên biến không được trùng với bất kỳ từ khóa nào trong Go.
  • Không có giới hạn độ dài của tên biến, nhưng tốt nhất là sử dụng độ dài tối ưu cho tên biến.

Khai báo một biến

Trong Go, các biến được khai báo bằng từ khóa "var", nhưng cũng có các cách khác để khai báo biến như chúng ta sẽ thấy sau trong hướng dẫn này. Hãy khám phá các cách khác nhau để khai báo biến.

Khai báo một biến đơn lẻ mà không có giá trị khởi tạo

Dưới đây là định dạng của một khai báo biến đơn lẻ mà không có giá trị khởi tạo được gán. Đầu tiên là từ khóa "var", thứ hai là tên của biến và thứ ba là kiểu của biến. Lưu ý khi giá trị không được cung cấp, thì biến được khởi tạo với giá trị mặc định của kiểu đó, cũng được gọi là giá trị zero của kiểu đó. Trong Go, giá trị mặc định hoặc giá trị zero của kiểu "int" là số không.

var <variable_name> <type>

Xem ví dụ bên dưới, nó khai báo một biến có tên "aaa" kiểu "int".

package main

import "fmt"

func main() {
    var aaa int
    fmt.Println(aaa)
}

Output: Nó sẽ in ra giá trị mặc định của kiểu "int", là số không.

0

Khai báo một biến đơn lẻ với giá trị khởi tạo

Dưới đây là định dạng của khai báo biến đơn lẻ với giá trị khởi tạo được gán. Mọi thứ giống như trên, chỉ có điều thêm vào là chúng ta gán giá trị cho biến ở cuối.

var <variable_name> <type> = <value>

Xem ví dụ bên dưới, nó khai báo một biến có tên "aaa" kiểu "int" và gán giá trị 8 cho nó.

package main

import "fmt"

func main() {
    var aaa int = 8
    fmt.Println(aaa)
}

Output:

8

Khai báo nhiều biến mà không có giá trị khởi tạo

Dưới đây là định dạng của khai báo nhiều biến mà không có giá trị khởi tạo được gán. Lưu ý rằng chỉ có thể khai báo các biến cùng kiểu với nhau. Kiểu được đặt ở cuối.

var <name1>, <name2>,….<nameN> <type>

Xem ví dụ bên dưới.

package main

import "fmt"

func main() {
    var aaa, bbb int
    fmt.Println(aaa)
    fmt.Println(bbb)
}

Output: Nó sẽ in ra giá trị mặc định hoặc giá trị zero của kiểu "int", là số 0 cho cả biến "aaa" và "bbb".

0
0

Khai báo nhiều biến với giá trị khởi tạo

Dưới đây là định dạng của khai báo nhiều biến với giá trị khởi tạo được gán. Lưu ý rằng chỉ có thể khai báo các biến cùng kiểu với nhau. Kiểu được đặt ở cuối.

var <name1>, <name2>, …..,<nameN> <type> = <value1>, <value2>, …..,<valueN>

Xem ví dụ mã dưới đây. Biến "aaa" và "bbb" được gán giá trị tương ứng là 8 và 9 trong một khai báo đơn.

package main

import "fmt"

func main() {
    var aaa, bbb int = 8, 9
    fmt.Println(aaa)
    fmt.Println(bbb)
}

Output:

8
9

Khai báo các biến khác kiểu dữ liệu

Dưới đây là định dạng để khai báo nhiều biến với các kiểu dữ liệu khác nhau. Giá trị có thể được gán hoặc không được gán cho biến tại thời điểm đó. Các biến mà không được gán giá trị sẽ nhận giá trị mặc định của kiểu đó. Trong ví dụ dưới đây, chúng ta thấy ba khai báo biến.

package main

import "fmt"

func main() {
    var (
        aaa int
        bbb int    = 8
        ccc string = "a"
    )

    fmt.Println(aaa)
    fmt.Println(bbb)
    fmt.Println(ccc)
}

Output:

0
8
a

Khai báo biến mà không có kiểu hoặc suy luận kiểu dữ liệu

Các biến cũng có thể được khai báo mà không cần chỉ định kiểu dữ liệu.

Trình biên dịch GO sẽ dựa trên giá trị được gán cho biến để xác định kiểu dữ liệu. Vì vậy, nếu biến có giá trị khởi tạo, thì kiểu có thể bị bỏ qua. Điều này còn được gọi là Suy luận kiểu dữ liệu. Dưới đây là định dạng cho khai báo như vậy.

var <varialbe_name> = <value>

Dưới đây là bảng suy luận kiểu cho các kiểu cơ bản trong Go như int, float, số phức, string, boolean, characters. Nó có nghĩa là nếu giá trị là một số nguyên thì kiểu của biến sẽ được suy luận là int, nếu giá trị là một số thực thì kiểu của biến được suy luận là float64, và tương tự cho các giá trị khác, dựa trên bảng dưới đây.

Integers int
Floats float64
Complex Numbers complex128
Strings string
Booleans bool
Characters int32 or rune

Các kiểu dữ liệu khác như Array, Pointer, Structure, vv, loại suy ra kiểu dữ liệu dựa trên giá trị của chúng. Dưới đây là một ví dụ minh họa cho điểm trên. Lưu ý rằng kiểu của biến t được suy ra chính xác là int vì giá trị được gán cho nó là 123 là kiểu int. Tương tự, kiểu của u cũng được suy ra chính xác là kiểu string vì giá trị được gán cho nó là một chuỗi.

Chú ý rằng kiểu của biến z được suy ra đúng là một cấu trúc main.sample.

package main

import "fmt"

func main() {
    var t = 123      //Type Inferred will be int
    var u = "circle" //Type Inferred will be string
    var v = 5.6      //Type Inferred will be float64
    var w = true     //Type Inferred will be bool
    var x = 'a'      //Type Inferred will be rune
    var y = 3 + 5i   //Type Inferred will be complex128
    var z = sample{name: "test"}  //Type Inferred will be main.Sample

    fmt.Printf("Type: %T Value: %v\n", t, t)
    fmt.Printf("Type: %T Value: %v\n", u, u)
    fmt.Printf("Type: %T Value: %v\n", v, v)
    fmt.Printf("Type: %T Value: %v\n", w, w)
    fmt.Printf("Type: %T Value: %v\n", x, x)
    fmt.Printf("Type: %T Value: %v\n", y, y)
    fmt.Printf("Type: %T Value: %v\n", z, z)
}
​​​​​​​
type sample struct {
    name string
}

Output:

Type: int Value: 123
Type: string Value: circle
Type: float64 Value: 5.6
Type: bool Value: true
Type: int32 Value: 97
Type: complex128 Value: (3+5i)
Type: main.sample Value: &{test}

Khai báo biến ngắn

Đối với khai báo biến, Go cung cấp một cách khác là sử dụng toán tử :=. Khi sử dụng toán tử :=, cả từ khóa var và thông tin về kiểu có thể bị bỏ qua. Dưới đây là định dạng cho khai báo biến này.

:=

Type inference sẽ xảy ra như đã được giải thích ở trên. Hãy xem một ví dụ hoạt động.

package main

import "fmt"

func main() {
    t := 123      //Type Inferred will be int
    u := "circle" //Type Inferred will be string
    v := 5.6      //Type Inferred will be float64
    w := true     //Type Inferred will be bool
    x := 'a'      //Type Inferred will be rune
    y := 3 + 5i   //Type Inferred will be complex128
    z := sample{name: "test"}  //Type Inferred will be main.Sample

    fmt.Printf("Type: %T Value: %v\n", t, t)
    fmt.Printf("Type: %T Value: %v\n", u, u)
    fmt.Printf("Type: %T Value: %v\n", v, v)
    fmt.Printf("Type: %T Value: %v\n", w, w)
    fmt.Printf("Type: %T Value: %v\n", x, x)
    fmt.Printf("Type: %T Value: %v\n", y, y)
    fmt.Printf("Type: %T Value: %v\n", z, z)
}
​​​​​​​
type sample struct {
    name string
}

Output

Type: int Value: 123
Type: string Value: circle
Type: float64 Value: 5.6
Type: bool Value: true
Type: int32 Value: 97
Type: complex128 Value: (3+5i)
Type: main.sample Value: &{test}

Một số điểm cần lưu ý về toán tử :=

  • Toán tử := chỉ có sẵn trong hàm. Nó không được phép ở bên ngoài hàm.
  • Một biến một khi đã được khai báo bằng := thì không thể khai báo lại bằng toán tử :=. Vì vậy, câu lệnh dưới đây sẽ gây ra lỗi biên dịch "no new variables in the left side of :=" .
a := 8
a := 16
  • Toán tử := cũng có thể được sử dụng để khai báo nhiều biến trong một dòng. Xem ví dụ dưới đây.
a,b := 1, 2
  • Trong trường hợp khai báo nhiều biến, := cũng có thể được sử dụng một lần nữa cho một biến cụ thể nếu ít nhất một trong số các biến ở phía bên trái là mới. Xem ví dụ dưới đây. Lưu ý rằng biến b được khai báo lại bằng :=. Điều này chỉ có thể xảy ra nếu ít nhất một trong số các biến là mới, trong trường hợp này là biến c. Trong trường hợp này, nó hoạt động như một phép gán cho biến b.
package main

import "fmt"

func main() {
    a, b := 1, 2
    b, c := 3, 4
    fmt.Println(a, b, c)
}

Output:

1, 3, 4

Những điểm quan trọng

  • Một biến không sử dụng sẽ được báo lỗi bởi trình biên dịch. Trình biên dịch GO không cho phép bất kỳ biến không sử dụng nào. Điều này là một tối ưu hóa trong GO. Điều tương tự cũng áp dụng cho hằng số như chúng ta sẽ thấy sau. Ví dụ dưới đây sẽ gây ra lỗi biên dịch.
a declared but not used
 
package main

func main() {
    var a = 1
}
  • Định nghĩa biến trong phạm vi nội tại có cùng tên với biến được định nghĩa trong phạm vi bên ngoài sẽ ẩn biến ở phạm vi bên ngoài.
package main

import "fmt"

var a = 123
​​​​​​​
func main() {
    var a = 456
    fmt.Println(a)
}

Output:

456
  • Biểu thức biến - Khi khai báo biến, biến cũng có thể được gán một biểu thức hoặc một lời gọi hàm. Xem ví dụ dưới đây.
    • Biến a được khai báo với biểu thức 5 + 3
    • Biến b được khai báo với một lời gọi hàm math.Max(4, 5), kết quả của hàm này sẽ được gán cho b khi chạy chương trình.
package main
import (
    "fmt"
    "math"
)
func main() {
    a := 5 + 3
    b := math.Max(4, 5)
    fmt.Println(a)
    fmt.Println(b)
}

Output:

8
5
  • Nếu một biến đã được khởi tạo với một kiểu dữ liệu cụ thể, thì không thể gán cho nó một giá trị thuộc kiểu dữ liệu khác sau này. Điều này cũng áp dụng cho khai báo ngắn gọn. Xem ví dụ dưới đây:
package main

func main() {
    var aaa int = 1
    aaa = "atest"
​​​​​​​
    bbb := 1
    bbb = "btest"
}

Output:

cannot use "atest" (type untyped string) as type int in assignment
cannot use "btest" (type untyped string) as type int in assignment

Đối với biến aaa, kiểu int đã được gán cho nó, do đó trình biên dịch sẽ báo lỗi khi gán một giá trị kiểu chuỗi cho nó. Với biến bbb, kiểu được suy ra là int, vì vậy nó cũng báo lỗi khi gán một giá trị kiểu chuỗi cho nó.

Phạm vi của biến (Biến cục bộ và biến toàn cục)

Phạm vi của một biến được định nghĩa ở mức gói (package level) hoặc mức hàm (function level) hoặc mức khối (block level). Phạm vi của một biến xác định nơi mà biến đó có thể truy cập và cũng như vòng đời của biến. Các biến trong Golang có thể được chia thành hai loại dựa trên phạm vi:

  • Biến cục bộ (Local Variable)
  • Biến toàn cục (Global Variable)

Biến cục bộ

  • Biến cục bộ là biến được định nghĩa trong một khối hoặc một hàm.
  • Một ví dụ của khối là vòng lặp for hoặc vòng lặp range.
  • Các biến này chỉ có thể truy cập từ bên trong khối hoặc hàm mà chúng được định nghĩa.
  • Các biến này chỉ tồn tại cho đến cuối khối hoặc hàm trong đó chúng được khai báo. Sau đó, chúng sẽ được thu dọn bởi bộ thu gom rác.

Xem ví dụ dưới đây:

  • Biến i không còn sẵn có sau vòng lặp for.
  • Tương tự, biến aaa không sẵn có bên ngoài hàm mà nó được khai báo.

Do đó, chương trình dưới đây sẽ gây ra lỗi biên dịch.

undefined: i
undefined: aaa

Code:

package main

import "fmt"

func main() {
    var aaa = "test"
    fmt.Println(aaa)
    for i := 0; i < 3; i++ {
        fmt.Println(i)
    }
    fmt.Println(i)
}
​​​​​​​
func testLocal() {
    fmt.Println(aaa)
}

Biến toàn cục

  • Một biến sẽ là global trong một package nếu nó được khai báo ở đầu tệp bên ngoài phạm vi bất kỳ hàm hoặc khối nào.
  • Nếu tên biến này bắt đầu bằng chữ cái thường thì nó có thể được truy cập từ trong package chứa định nghĩa biến này.
  • Nếu tên biến bắt đầu bằng chữ cái in hoa thì nó có thể được truy cập từ bên ngoài package khác với package nó được khai báo.
  • Biến toàn cục có sẵn trong suốt thời gian chạy của một chương trình.

Ví dụ trong chương trình dưới đây, biến aaa sẽ là biến toàn cục có sẵn trong toàn bộ package main. Nó sẽ có sẵn trong bất kỳ hàm nào bên trong package main. Lưu ý rằng tên biến sẽ không có sẵn bên ngoài package main vì tên của nó bắt đầu bằng chữ cái thường.

package main

import "fmt"

var aaa = "test"

func main() {
    testGlobal()
}
​​​​​​​
func testGlobal() {
    fmt.Println(aaa)
}

Output:

test

Tổng kết

Đó là tất cả những thông tin về biến trong Golang. Hy vọng bạn đã thích bài viết này. Vui lòng chia sẻ phản hồi hoặc cải tiến hoặc những sai sót trong phần bình luận.

 
 
 
 
Tag: golang cơ bản go