[Golang cơ bản] Pointer trong golang

Post on: 2023-03-06 23:42:03 | in: Golang
Pointer là một biến chứa địa chỉ bộ nhớ của một biến khác.

Khai báo con trỏ

Trong ví dụ dưới đây, ex là con trỏ kiểu T.

var ex *T

Trong khai báo, giá trị của con trỏ được thiết lập mặc định là giá trị zero, tức là nil.

Khởi tạo con trỏ

Có hai cách để khởi tạo con trỏ:

  • Sử dụng toán tử new
  • Sử dụng toán tử ‘&’ (ampersand)

Sử dụng toán tử new.

Con trỏ có thể được khởi tạo bằng toán tử new.

a := new(int)
*a = 10
fmt.Println(*a) //Output will be 10

Toán tử * có thể được sử dụng để giải tham chiếu một con trỏ, có nghĩa là lấy giá trị tại địa chỉ được lưu trữ trong con trỏ.

fmt.Println(*a) //Print the value stored at address a

Sử dụng toán tử ‘&’ (ampersand).

& được sử dụng để lấy địa chỉ của một biến.

a := 2
b := &a
fmt.Println(*b) //Output will be 2

Hãy xem một đoạn mã hoạt động bao gồm tất cả các điểm đã đề cập trên.

package main

import "fmt"

func main() {
    //Declare
    var b *int
    a := 2
    b = &a

    //Will print a address. Output will be different everytime.
    fmt.Println(b)
    fmt.Println(*b)
    b = new(int)
    *b = 10
    fmt.Println(*b)
}

Output:

2
10
0xc0000b0018

Về toán tử * hoặc giải tham chiếu con trỏ.

Toán tử * có thể được sử dụng để:

  • Giải tham chiếu một con trỏ, có nghĩa là lấy giá trị tại địa chỉ được lưu trữ trong con trỏ.
  • Thay đổi giá trị tại vị trí con trỏ đang trỏ đến.
package main

import "fmt"

func main() {
a := 2
b := &a
fmt.Println(a)
fmt.Println(*b)

*b = 3
fmt.Println(a)
fmt.Println(*b)

a = 4
fmt.Println(a)
fmt.Println(*b)
}

Output

2
2
3
3
4
4

Cả a và *b đều tham chiếu đến cùng một biến bên trong. Do đó, thay đổi giá trị của một cái sẽ phản ánh vào cái còn lại. Ngoài ra, * và & có thể được sử dụng cùng nhau. Nhưng chúng sẽ hủy bỏ lẫn nhau.

Do đó, hai câu sau đây tương đương và sẽ in ra giá trị 2.

  • a
  • *&a

Ngoài ra, ba câu sau đây tương đương và sẽ in địa chỉ của biến a được lưu trữ trong biến b.

  • b
  • *&b
  • &*b

Lưu ý: *a không phải là một phép toán hợp lệ vì a không phải là một con trỏ.

Con trỏ đến một con trỏ.

Cũng có thể tạo một con trỏ đến một con trỏ trong Go.

a := 2
b := &a
c := &b

Trong đoạn mã, c là một con trỏ đến một con trỏ. Nó lưu trữ địa chỉ của b, và b lưu trữ địa chỉ của a. Chúng ta có thể sử dụng toán tử * để giải tham chiếu hai lần để in giá trị được lưu trữ tại con trỏ đến con trỏ. Do đó, **c sẽ in ra giá trị 2.

Để minh họa, hình dưới đây mô tả con trỏ đến con trỏ.

  • b chứa địa chỉ của a
  • c chứa địa chỉ của b.

Hãy xem một chương trình minh họa về con trỏ đến con trỏ.

package main

import "fmt"

func main() {
a := 2
b := &a
c := &b

fmt.Printf("a: %d\n", a)
fmt.Printf("b: %x\n", b)
fmt.Printf("c: %x\n", c)

fmt.Println()
fmt.Printf("a: %d\n", a)
fmt.Printf("*&a: %d\n", *&a)
fmt.Printf("*b: %d\n", *b)
fmt.Printf("**c: %d\n", **c)

fmt.Println()
fmt.Printf("&a: %d\n", &a)
fmt.Printf("b: %d\n", b)
fmt.Printf("&*b: %d\n", &*b)
fmt.Printf("*&b: %d\n", *&b)
fmt.Printf("*c: %d\n", *c)

fmt.Println()
fmt.Printf("b: %d\n", &b)
fmt.Printf("*c: %d\n", c)
}

Output

a: 2
b: c000018078
c: c00000e028


a: 2
*&a: 2
*b: 2
**c: 2

&a: 824633819256
b: 824633819256
&*b: 824633819256
*&b: 824633819256
*c: 824633819256

b: 824633778216
*c: 824633778216

Từ đầu ra, ta có thể thấy rằng:

Các câu lệnh sau đây tương đương và bằng với giá trị của biến a, là 2:

  • a
  • *&a
  • *b
  • **c

Các câu lệnh sau đây tương đương và bằng với giá trị của biến b, là địa chỉ của a:

  • &a
  • b
  • &*b
  • *&b
  • *c

Các câu lệnh sau đây tương đương và bằng với giá trị của biến c, là địa chỉ của b:

  • b
  • *c

Pointer Arithmetic

Đúng, toán học con trỏ không được hỗ trợ trong Go giống như trong C/C++. Khi thử sử dụng các toán tử số học trên con trỏ, Go sẽ phát sinh một lỗi biên dịch.

package main
func main() {
    a := 1
    b := &a
    b = b + 1
}

Output

Chương trình sẽ phát sinh lỗi biên dịch

invalid operation: b + 1 (mismatched types *int and int)

Giá trị zero mặc định của con trỏ

Giá trị zero mặc định của một con trỏ là nil.. Hãy xem một chương trình cho nó

package main

import "fmt"

func main() {
    var a *int
    fmt.Print("Default Zero Value of a pointer: ")
    fmt.Println(a)
}

Output:

Default value of pointer:

Kết luận

Đây là tất cả về con trỏ trong golang. Hy vọng bạn đã thích bài viết này. Vui lòng chia sẻ phản hồi/cải tiến/sai lầm trong nhận xét.

Tag: golang cơ bản go