[Golang cơ bản] Struct trong Golang

Post on: 2023-03-09 22:34:47 | in: Golang
GO struct được đặt tên là bộ sưu tập các trường dữ liệu có thể thuộc các loại khác nhau.

Tổng quan

Struct hoạt động như một bộ chứa có các loại dữ liệu không đồng nhất khác nhau cùng đại diện cho một thực thể. Ví dụ, các thuộc tính khác nhau được sử dụng để đại diện cho một nhân viên trong một tổ chức. Nhân viên có thể có

  • Name kiểu string
  • Age kiểu int
  • DOB kiểu  time.Time
  • Salary kiểu int

.. và như thế. Một struct có thể được sử dụng để đại diện cho một nhân viên

type employee struct {
    name   string
    age    int
    salary int
}

Một struct trong Golang có thể được so sánh với một class trong các ngôn ngữ hướng đối tượng.

Khai báo một kiểu struct

Dưới đây là định dạng cho việc khai báo một kiểu struct

type struct_name struct {
    field_name1 field_type1
    field_name2 field_type2
    ...
}

Trong định dạng trên, struct_name là tên của struct. Nó có một trường tên là field_name1 có kiểu field_type1 và một trường tên là field_name2 có kiểu field_type2. Điều này khai báo một kiểu struct có tên mới, hoạt động như một bản thiết kế. Từ khóa type được sử dụng để giới thiệu một kiểu mới

Ví dụ

type point struct {
    x float64
    y float64
}

Đoạn khai báo trên khai báo một kiểu struct mới có tên là point có hai trường x và y. Cả hai trường đều có kiểu float64. Khi một kiểu struct mới được khai báo, chúng ta có thể định nghĩa biến struct cụ thể mới từ nó, như chúng ta sẽ thấy trong phần tiếp theo.

Tạo một biến struct

Khai báo một struct chỉ khai báo một kiểu struct có tên. Tạo một biến struct tạo ra một thể hiện của kiểu struct đó với bộ nhớ được khởi tạo. Chúng ta có thể tạo một biến struct rỗng mà không cần cung cấp giá trị cho bất kỳ trường nào.

emp := employee{}

Trong trường hợp này, tất cả các trường trong struct được khởi tạo với giá trị mặc định của kiểu trường đó.

Chúng ta cũng có thể khởi tạo giá trị cho từng trường struct trong quá trình tạo biến struct. Có hai biến thể:

  • Mỗi trường trên cùng một dòng.
emp := employee{name: "Sam", age: 31, salary: 2000}
  • Mỗi trường trên các dòng khác nhau
emp := employee{
   name:   "Sam",
   age:    31,
   salary: 2000,
}

Cũng có thể khởi tạo chỉ một số trường với giá trị. Các trường không được khởi tạo sẽ có giá trị mặc định bằng giá trị không của kiểu của chúng.

emp := employee{
   name: "Sam",
   age: 31,
}

Trong trường hợp trên, trường lương sẽ nhận giá trị mặc định là 0 vì nó không được khởi tạo.

Hãy xem một đoạn code minh họa làm việc với các điểm trên:

package main

import "fmt"

type employee struct {
    name   string
    age    int
    salary int
}

func main() {
    emp1 := employee{}
    fmt.Printf("Emp1: %+v\n", emp1)

    emp2 := employee{name: "Sam", age: 31, salary: 2000}
    fmt.Printf("Emp2: %+v\n", emp2)
    emp3 := employee{
        name:   "Sam",
        age:    31,
        salary: 2000,
    }
    fmt.Printf("Emp3: %+v\n", emp3)
    emp4 := employee{
        name: "Sam",
        age:  31,
    }
    fmt.Printf("Emp4: %+v\n", emp4)
}

Output

Emp1: {name: age:0 salary:0}
Emp2: {name:Sam age:31 salary:2000}
Emp3: {name:Sam age:31 salary:2000}
Emp4: {name:Sam age:31 salary:0}

Trong chương trình trên:

  • Chúng ta trước tiên khai báo một struct employee.
  • Các trường của emp1 được khởi tạo với giá trị mặc định bằng giá trị không của kiểu của nó, tức là name là "", age và salary là 0.
  • emp2 đã được khởi tạo với tất cả các trường trên cùng một dòng. Các trường của nó được in ra chính xác với giá trị của chúng.
  • emp3 được khởi tạo với tất cả các trường trên các dòng khác nhau. Các trường của nó được in ra chính xác với giá trị tương ứng.
  • Trường salary của emp4 được khởi tạo với giá trị mặc định bằng 0. Trong khi đó hai trường khác được in ra chính xác với giá trị tương ứng.
Lưu ý rằng khi khởi tạo một struct, mỗi dòng mới trong dấu ngoặc nhọn phải kết thúc bằng một dấu phẩy. Do đó, khởi tạo dưới đây sẽ gây lỗi:"
"salary" : 2000

không kết thúc bằng dấu phẩy.

emp := employee{
  name:   "Sam",
  age:    31,
  salary: 2000
}

Điều này sẽ hoạt động bình thường.

emp := employee{
  name:   "Sam",
  age:    31,
  salary: 2000}

Không có tên trường

Struct cũng có thể được khởi tạo mà không cần chỉ định tên trường. Tuy nhiên, trong trường hợp này, tất cả các giá trị cho mỗi trường phải được cung cấp theo thứ tự.

emp := employee{"Sam", 31, 2000}

Nếu không cung cấp tất cả các giá trị khi không sử dụng tên trường, một lỗi trình biên dịch sẽ được phát sinh.

Chúng ta hãy xem một chương trình.

package main

import "fmt"

type employee struct {
    name   string
    age    int
    salary int
}

func main() {
    emp := employee{"Sam", 31, 2000}
    fmt.Printf("Emp: %+v\n", emp)
    //emp = employee{"Sam", 31}
}

Output

Emp2: {name:Sam age:31 salary:2000}

Bỏ chú thích cho dòng đó.

emp = employee{"Sam", 31}

bỏ chú thích cho dòng đó trong chương trình trên, và nó sẽ phát sinh lỗi trình biên dịch.

too few values in employee literal

Truy cập và thiết lập Trường Struct

Các trường Struct có thể được truy cập bằng toán tử chấm. Dưới đây là định dạng để lấy giá trị.

n := emp.name

Tương tự, một giá trị có thể được gán cho một trường struct.

emp.name = "some_new_name"
 
package main

import "fmt"

type employee struct {
    name   string
    age    int
    salary int
}

func main() {
    emp := employee{name: "Sam", age: 31, salary: 2000}

    //Accessing a struct field
    n := emp.name
    fmt.Printf("Current name is: %s\n", n)

    //Assigning a new value
    emp.name = "John"
    fmt.Printf("New name is: %s\n", emp.name)
}

Output

Current name is: Sam
New name is: John

Con trỏ đến một struct

Có hai cách để tạo con trỏ đến struct:

  • Sử dụng toán tử &
  • Sử dụng từ khóa new

Hãy xem xét từng phương pháp một.

Sử dụng toán tử &

Toán tử & có thể được sử dụng để lấy con trỏ đến một biến struct.

emp := employee{name: "Sam", age: 31, salary: 2000}
empP := &emp

Con trỏ đến struct cũng có thể được tạo trực tiếp.

empP := &employee{name: "Sam", age: 31, salary: 2000}

Chúng ta hãy xem một chương trình.

package main

import "fmt"

type employee struct {
    name   string
    age    int
    salary int
}

func main() {
    emp := employee{name: "Sam", age: 31, salary: 2000}
    empP := &emp
    fmt.Printf("Emp: %+v\n", empP)
    empP = &employee{name: "John", age: 30, salary: 3000}
    fmt.Printf("Emp: %+v\n", empP)
}

Output

Emp: &{name:Sam age:31 salary:2000}
Emp: &{name:John age:30 salary:3000}

Sử dụng từ khóa new()

Sử dụng từ khóa new() sẽ:

  • Tạo ra struct
  • Khởi tạo tất cả các trường với giá trị mặc định zero của kiểu dữ liệu tương ứng.
  • Trả về con trỏ tới struct vừa được tạo.

Điều này sẽ trả về một con trỏ.

empP := new(employee)

Địa chỉ con trỏ có thể in ra bằng cách sử dụng định dạng %p.

fmt.Printf("Emp Pointer: %p\n", empP)

Toán tử giải tham chiếu '*' có thể được sử dụng để in ra giá trị tại địa chỉ mà con trỏ trỏ đến.

fmt.Printf("Emp Value: %+v\n", *empP)

Nó sẽ in ra

Emp Value: {name: age:0 salary:0}

Khi không sử dụng con trỏ gián tiếp nhưng sử dụng định dạng % +v, thì dấu & sẽ được thêm vào trước cấu trúc chỉ ra rằng đó là một con trỏ.

fmt.Printf("Emp Value: %+v\n", empP)

Nó sẽ in ra

Emp Value: &{name: age:0 salary:0}

Hãy xem chương trình đầy đủ thể hiện các điểm trên

package main

import "fmt"

type employee struct {
    name   string
    age    int
    salary int
}

func main() {
    empP := new(employee)
    fmt.Printf("Emp Pointer Address: %p\n", empP)
    fmt.Printf("Emp Pointer: %+v\n", empP)
    fmt.Printf("Emp Value: %+v\n", *empP)
}

Output

Emp Pointer Address: 0xc000130000
Emp Pointer: &{name: age:0 salary:0}
Emp Value: {name: age:0 salary:0}

In ra biến Struct

Có hai cách để in tất cả các biến struct bao gồm tất cả các khóa và giá trị của nó.

  • Sử dụng fmt package
  • In struct ở dạng JSON sử dụng gói json/encoding. Điều này cũng cho phép in đẹp một cấu trúc dữ liệu.

Hãy xem hai cách mà chúng ta có thể in ra các instance của cấu trúc employee.

Sử dụng fmt package

Hàm fmt.Printf() có thể được sử dụng để in một struct. Các định dạng khác nhau có thể được sử dụng để in một struct theo các cách khác nhau. Hãy xem cách các định dạng khác nhau có thể được sử dụng để in một struct theo các định dạng khác nhau.

Hãy tạo một trường hợp của struct employee.

emp := employee{name: "Sam", age: 31, salary: 2000}
  • %v – Nó sẽ in ra chỉ các giá trị. Tên trường sẽ không được in ra. Đây là cách mặc định để in một struct. Ví dụ:
fmt.Printf("%v", emp)  -  {Sam 31 2000}
  • %+v – Giá trị của trường và tên trường sẽ được in ra. Ví dụ:
fmt.Printf("%+v", emp) - {name:Sam age:31 salary:2000}

Hàm fmt.Println() cũng có thể được sử dụng để in ra một struct. Vì %v là giá trị mặc định cho hàm fmt.Printlin(), do đó kết quả sẽ giống như sử dụng %v cho hàm fmt.Printf().

fmt.Println(emp) - {Sam 31 2000}

Chúng ta hãy xem một chương trình hoạt động như sau

package main

import "fmt"

type employee struct {
    name   string
    age    int
    salary int
}

func main() {
    emp := employee{name: "Sam", age: 31, salary: 2000}
    fmt.Printf("Emp: %v\n", emp)
    fmt.Printf("Emp: %+v\n", emp)
    fmt.Printf("Emp: %#v\n", emp)
    fmt.Println(emp)
}

Output

Emp: {Sam 31 2000}
Emp: {name:Sam age:31 salary:2000}
Emp: main.employee{name:"Sam", age:31, salary:2000}
{Sam 31 2000}

In ra struct ở dạng JSON

Phương pháp thứ hai để in ra struct dưới dạng JSON. Hàm Marshal và MarshalIndent của package encoding/json có thể được sử dụng để in ra một struct dưới dạng định dạng JSON. Dưới đây là sự khác biệt:

  • Marshal - Dưới đây là chữ ký của hàm Marshal. Hàm này trả về mã hóa JSON của v bằng cách duyệt giá trị đệ quy.
Marshal(v interface{}) ([]byte, error)
  • Hàm MarshalIndent - Dưới đây là chữ ký của hàm MarshalIndent. Nó tương tự như hàm Marshal nhưng áp dụng Indent để định dạng đầu ra. Do đó, nó có thể được sử dụng để in đẹp một struct.
MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

Được lưu ý rằng cả hai hàm Marshal và MarshalIndent chỉ có thể truy cập đến các trường được xuất của một struct, có nghĩa là chỉ các trường được viết hoa mới có thể được truy cập và mã hóa dưới dạng JSON.

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type employee struct {
    Name   string
    Age    int
    salary int
}

func main() {
    emp := employee{Name: "Sam", Age: 31, salary: 2000}
    //Marshal
    empJSON, err := json.Marshal(emp)
    if err != nil {
        log.Fatalf(err.Error())
    }
    fmt.Printf("Marshal funnction output %s\n", string(empJSON))

    //MarshalIndent
    empJSON, err = json.MarshalIndent(emp, "", "  ")
    if err != nil {
        log.Fatalf(err.Error())
    }
    fmt.Printf("MarshalIndent funnction output %s\n", string(empJSON))
}

Output:

Marshal funnction output {"Name":"Sam","Age":31}

MarshalIndent funnction output {
  "Name": "Sam",
  "Age": 31
}

Trường hợp trường salary không được in ra trong output bởi vì nó bắt đầu bằng một chữ cái thường và không được xuất khẩu. Hàm Marshal không định dạng output trong khi hàm MarshalIndent thì có.

Trong Golang, ta có thể sử dụng struct meta fields để định nghĩa tên khóa (key name) cho JSON encoded struct khác với tên field trong struct. Ta sẽ thấy ví dụ về điều này ở phần tiếp theo.

Struct Field Meta hoặc Tags

Một struct trong go cũng cho phép thêm siêu dữ liệu vào các trường của nó. Các trường meta này có thể được sử dụng để mã hóa giải mã vào các dạng khác nhau, thực hiện một số hình thức kiểm tra hợp lệ trên các trường struct, vv Vì vậy, về cơ bản, bất kỳ thông tin meta nào cũng có thể được lưu trữ với các trường của một struct và có thể được sử dụng bởi bất kỳ gói hoặc thư viện nào cho các mục đích khác nhau.

Dưới đây là định dạng để đính kèm một dữ liệu meta. Meta-data là một chuỗi ký tự nghĩa là nó được bao quanh bởi dấu backquotes (`)

type strutName struct{
   fieldName type `key:value key2:value2`
}

Bây giờ với trường hợp sử dụng của chúng ta, chúng ta sẽ thêm các thẻ JSON vào struct employee như dưới đây. Hàm Marshal sẽ sử dụng tên khóa được chỉ định trong các thẻ.

type employee struct {
    Name   string `json:"n"`
    Age    int    `json:"a"`
    Salary int    `json:"s"`
}

Hãy xem toàn bộ chương trình

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type employee struct {
    Name   string `json:"n"`
    Age    int    `json:"a"`
    Salary int    `json:"s"`
}

func main() {
    emp := employee{Name: "Sam", Age: 31, Salary: 2000}
    //Converting to jsonn
    empJSON, err := json.MarshalIndent(emp, '', '  ')
    if err != nil {
        log.Fatalf(err.Error())
    }
    fmt.Println(string(empJSON))
}

Output:

{
  "n": "Sam",
  "a": 31,
  "s": 2000
}

Tên khóa trong kết quả đầu ra giống như được chỉ định trong các thẻ meta JSON.

Trường ẩn danh trong một Struct

Một struct có thể có các trường vô danh, có nghĩa là một trường không có tên. Kiểu dữ liệu sẽ trở thành tên trường. Trong ví dụ dưới đây, "string" sẽ trở thành tên trường.

type employee struct {
    string
    age    int
    salary int
}

Trường ẩn danh cũng có thể được truy cập và gán giá trị

package main

import "fmt"

type employee struct {
    string
    age    int
    salary int
}

func main() {
    emp := employee{string: "Sam", age: 31, salary: 2000}
    //Accessing a struct field
    n := emp.string
    fmt.Printf("Current name is: %s\n", n)
    //Assigning a new value
    emp.string = "John"
    fmt.Printf("New name is: %s\n", emp.string)
}

Output

Current name is: Sam
New name is: John

Struct lồng nhau

Một struct có thể chứa một struct khác lồng trong đó. Hãy xem ví dụ về một struct lồng nhau. Trong đoạn code dưới đây, struct employee có struct address được lồng trong đó.

package main

import "fmt"

type employee struct {
    name    string
    age     int
    salary  int
    address address
}

type address struct {
    city    string
    country string
}

func main() {
    address := address{city: "London", country: "UK"}
    emp := employee{name: "Sam", age: 31, salary: 2000, address: address}
    fmt.Printf("City: %s\n", emp.address.city)
    fmt.Printf("Country: %s\n", emp.address.country)
}

Output

City: London
Country: UK

Chú ý cách truy cập các trường của struct lồng nhau.

emp.address.city
emp.address.country

Anonymous nested struct fields

Trường hợp nested struct field có thể là anonymous. Và ở trường hợp này, các trường của nested struct được truy cập trực tiếp. Vì vậy, dưới đây là hợp lệ.

emp.city
emp.country

Điều cần lưu ý là dưới đây vẫn là hợp lệ trong trường hợp này.

emp.address.city
emp.address.country

Hãy xem một chương trình

package main

import "fmt"

type employee struct {
name   string
age    int
salary int
address
}

type address struct {
city    string
country string
}

func main() {
address := address{city: "London", country: "UK"}

 emp := employee{name: "Sam", age: 31, salary: 2000, address: address}

 fmt.Printf("City: %s\n", emp.address.city)
fmt.Printf("Country: %s\n", emp.address.country)

 fmt.Printf("City: %s\n", emp.city)
fmt.Printf("Country: %s\n", emp.country)
}

Output

City: London
Country: UK
City: London
Country: UK

Trong chương trình trên, chúng ta có thể truy cập trường city của cấu trúc address theo hai cách.

emp.city
emp.address.city

Tương tự cho trường country của struct address.

Exported and UnExported fields of a struct

Go không có các từ khóa public, private hoặc protected. Cơ chế duy nhất để kiểm soát khả năng nhìn thấy bên ngoài package là sử dụng định dạng chữ viết hoa và chữ thường.

  • Các Identifier viết hoa được xuất khẩu. Chữ in hoa cho thấy đây là một identifier được xuất khẩu và có sẵn bên ngoài package.
  • Các identifier chữ thường không được xuất khẩu. Chữ thường cho thấy rằng identifier không được xuất khẩu và chỉ có thể được truy cập từ cùng package.

Do đó, bất kỳ struct nào bắt đầu bằng chữ hoa đều được export tới các package khác. Tương tự, bất kỳ trường struct nào bắt đầu bằng chữ hoa đều được export, còn không thì không. Chúng ta hãy xem một ví dụ dưới đây, thể hiện sự xuất khẩu và không xuất khẩu của struct và các trường struct. Xem tệp model.go và test.go dưới đây. Cả hai thuộc gói main.

  • Cấu trúc
    • Cấu trúc Person được xuất khẩu (exported)
    • Cấu trúc company không được xuất khẩu (non-exported)
  • Đối tượng (struct)
    • Struct Person trường Name được xuất khẩu (exported)
    • Struct Person trường age không được xuất khẩu nhưng Name thì được

model.go

package main

import "fmt"

//Person struct
type Person struct {
    Name string
    age  int
}

type company struct {
}

Để viết một tập tin test.go trong cùng gói main. Xem dưới đây.

test.go

package main

import "fmt"

//Test function
func Test() {
    //STRUCTURE IDENTIFIER
    p := &Person{
        Name: "test",
        age:  21,
    }
    fmt.Println(p)
    c := &company{}
    fmt.Println(c)

    //STRUCTURE'S FIELDS
    fmt.Println(p.Name)
    fmt.Println(p.age)
}

Khi chạy file này, nó có thể truy cập được tất cả các trường đã xuất và không được xuất trong file model.go vì cả hai đều thuộc cùng gói main. Không có lỗi biên dịch và nó sẽ đưa ra đầu ra như sau:

Output:

&{test 21}
&{}
test
21

Khi chuyển file model.go vào một package khác tên là "model", chúng ta sẽ thấy thông báo lỗi khi thực hiện 'go build'. Tất cả các lỗi biên dịch đều xuất hiện bởi vì test.go trong package main không thể tham chiếu đến các trường không được xuất (un-exported) của model.go trong package model.

model.go

package model

//Person struct
type Person struct {
Name string
age  int
}

type company struct {
}

test.go

package main

import (
"fmt"
        //This will path of your model package
"/model"
)

//Test function
func main() {
//STRUCTURE IDENTIFIER
p := &model.Person{
  Name: "test",
  age:  21,
}
fmt.Println(p)
c := &model.company{}
fmt.Println(c)

 //STRUCTURE'S FIELDS
fmt.Println(p.Name)
fmt.Println(p.age)
}

Output:

cannot refer to unexported name model.company
p.age undefined (cannot refer to unexported field or method age)

Struct Equality

Trước khi xem xét tính bằng nhau của struct, điều quan trọng cần biết là tất cả các trường trong struct có kiểu dữ liệu có thể so sánh được hay không.

Một số kiểu dữ liệu có thể so sánh được được định nghĩa bởi go specification như sau:

  • boolean
  • numeric
  • string,
  • pointer
  • channel
  • interface types
  • structs – Nếu tất cả các trường của nó đều có kiểu so sánh được.
  • array – Nếu kiểu giá trị của phần tử mảng là có thể so sánh.

Một số kiểu dữ liệu không thể so sánh được theo đặc tả của Go và không thể được sử dụng làm khóa trong bản đồ (map) bao gồm:

  • Slice
  • Map
  • Function

Hai struct sẽ bằng nhau nếu tất cả các loại trường của chúng có thể so sánh và tất cả các giá trị trường tương ứng đều bằng nhau. Hãy xem một ví dụ.

package main

import "fmt"

type employee struct {
    name   string
    age    int
    salary int
}

func main() {
    emp1 := employee{name: "Sam", age: 31, salary: 2000}
    emp2 := employee{name: "Sam", age: 31, salary: 2000}
    if emp1 == emp2 {
        fmt.Println("emp1 annd emp2 are equal")
    } else {
        fmt.Println("emp1 annd emp2 are not equal")
    }
}

Output

emp1 annd emp2 are equal

Nếu kiểu trường của struct không thể so sánh được thì sẽ có lỗi biên dịch khi kiểm tra tính bằng nhau của hai struct bằng toán tử ==.

package main
import "fmt"
type employee struct {
    name        string
    age         int
    salary      int
    departments []string
}
func main() {
    emp1 := employee{name: "Sam", age: 31, salary: 2000, departments: []string{"CS"}}
    emp2 := employee{name: "Sam", age: 31, salary: 2000, departments: []string{"EC"}}
    if emp1 == emp2 {
        fmt.Println("emp1 annd emp2 are equal")
    } else {
        fmt.Println("emp1 annd emp2 are not equal")
    }
}

Chương trình trên sẽ gây ra lỗi biên dịch vì struct employee chứa một trường departments là một slice các string. slice không phải là một kiểu có thể so sánh và do đó sẽ gây lỗi biên dịch khi so sánh các struct.

invalid operation: emp1 == emp2 (struct containing []string cannot be compared)

Các struct là kiểu giá trị

Một struct là kiểu giá trị trong Go. Vì vậy, tên biến của một struct không phải là một con trỏ đến struct, thực tế nó đại diện cho toàn bộ struct. Một bản sao mới của struct sẽ được tạo ra khi:

  • Một biến struct được gán cho một biến struct khác.
  • Một biến struct được truyền như một đối số đến một hàm.

Hãy xem ví dụ trên với một ví dụ khác.

package main

import "fmt"

type employee struct {
    name   string
    age    int
    salary int
}

func main() {
    emp1 := employee{name: "Sam", age: 31, salary: 2000}
    fmt.Printf("Emp1 Before: %v\n", emp1)

    emp2 := emp1

    emp2.name = "John"
    fmt.Printf("Emp1 After assignment: %v\n", emp1)
    fmt.Printf("Emp2: %v\n", emp2)

    test(emp1)
    fmt.Printf("Emp1 After Test Function Call: %v\n", emp1)
}

func test(emp employee) {
    emp.name = "Mike"
    fmt.Printf("Emp in Test function: %v\n", emp)
}

Output

Emp1 Before: {Sam 31 2000}
Emp1 After assignment: {Sam 31 2000}
Emp2: {John 31 2000}
Emp in Test function: {Mike 31 2000}
Emp1 After Test Function Call: {Sam 31 2000}

Trong ví dụ trên,

  • Chúng ta gán emp1 cho emp2 và sau đó thay đổi giá trị của trường name của emp2. Sau đó, khi chúng ta in emp1, ta thấy rằng nó không thay đổi. Điều này xảy ra vì khi chúng ta gán emp1 cho emp2, một bản sao được tạo và thay đổi emp2 không có bất kỳ tác động nào đến emp1.
  • Chúng ta truyền emp1 vào hàm test và sau đó lại thay đổi trường name của nó trong hàm test. Sau đó, khi chúng ta in emp1, ta thấy rằng nó không thay đổi. Lý do tương tự, khi emp1 được truyền như là đối số cho hàm test, một bản sao của emp1 được tạo ra.

Kết luận

Đây là tất cả về struct trong golang. Trong bài viết này, chúng ta đã học các cách khác nhau để khởi tạo một struct, con trỏ tới struct, các cách in khác nhau, về các trường ẩn danh, v.v. Tôi 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 sót trong phần nhận xét.

Tag: golang cơ bản go