关于go:如何快速学习Go的struct数据类型

本文已收录如何疾速学习Go的struct数据类型。涵盖PHP、JavaScript、Linux、Golang、MySQL、Redis和开源工具等等相干内容。

什么是构造体

构造是示意字段汇合的用户定义类型。它能够用于将数据分组为单个单元而不是将每个数据作为独自的值的中央。
例如,员工有firstName、lastName和age。将这三个属性分组到一个名为Employee

type Employee struct {  
    firstName string
    lastName  string
    age       int
}

下面的代码段申明了一个构造类型Employee,其中蕴含字段firstName、lastName和age。下面的Employee构造称为命名构造,因为它创立了一个名为Employme的新数据类型,能够应用该数据类型创立Employ构造。
通过在一行中申明属于同一类型的字段,而后在类型名称前面加上该字段,也能够使该构造更加紧凑。在下面的struct中,firstName和lastName属于同一类型字符串,因而该struct能够重写为:

type Employee struct {  
    firstName, lastName string
    age                 int
}

只管下面的语法节俭了几行代码,但它并没有使字段声显著式。请防止应用上述语法。

创立构造体

让咱们应用以下简略程序申明一个命名的structEmployee。

package main

import (  
    "fmt"
)

type Employee struct {  
    firstName string
    lastName  string
    age       int
    salary    int
}

func main() {

    //creating struct specifying field names
    emp1 := Employee{
        firstName: "Sam",
        age:       25,
        salary:    500,
        lastName:  "Anderson",
    }

    //creating struct without specifying field names
    emp2 := Employee{"Thomas", "Paul", 29, 800}

    fmt.Println("Employee 1", emp1)
    fmt.Println("Employee 2", emp2)
}

在上述程序的第7行中,咱们创立了一个命名的构造类型Employee。在上述程序的第17行中,emp1构造是通过为每个字段名指定值来定义的。申明构造类型时,字段的程序不用与字段名的程序雷同。在这种状况下。咱们已更改lastName的地位并将其移到开端。这将不会有任何问题。
在上述程序的第25行中,通过省略字段名来定义emp2。在这种状况下,必须放弃字段的程序与构造申明中指定的程序雷同。请防止应用此语法,因为它会使您难以确定哪个字段的值。咱们在此处指定此格局只是为了了解这也是一个无效语法:)
以上程序打印为:

Employee 1 {Sam Anderson 25 500}  
Employee 2 {Thomas Paul 29 800}  

创立匿名构造体

能够在不创立新数据类型的状况下申明构造。这些类型的构造称为匿名构造。

package main

import (  
    "fmt"
)

func main() {  
    emp3 := struct {
        firstName string
        lastName  string
        age       int
        salary    int
    }{
        firstName: "Andreah",
        lastName:  "Nikola",
        age:       31,
        salary:    5000,
    }

    fmt.Println("Employee 3", emp3)
}

在上述程序的第8行中,定义了一个匿名构造变量emp3。正如咱们曾经提到的,这个构造称为anonymous,因为它只创立一个新的构造变量emp3,而没有定义任何新的构造类型,如命名构造。

上述代码打印的后果为:

Employee 3 {Andreah Nikola 31 5000}  

拜访构造体字段

运算符.用于拜访构造的各个字段。

package main

import (  
    "fmt"
)

type Employee struct {  
    firstName string
    lastName  string
    age       int
    salary    int
}

func main() {  
    emp6 := Employee{
        firstName: "Sam",
        lastName:  "Anderson",
        age:       55,
        salary:    6000,
    }
    fmt.Println("First Name:", emp6.firstName)
    fmt.Println("Last Name:", emp6.lastName)
    fmt.Println("Age:", emp6.age)
    fmt.Printf("Salary: $%d\n", emp6.salary)
    emp6.salary = 6500
    fmt.Printf("New Salary: $%d", emp6.salary)
}

下面程序中的emp6.firstName拜访emp6构造的firstName字段。在第25行中,咱们批改了员工的工资。此程序打印。

First Name: Sam  
Last Name: Anderson  
Age: 55  
Salary: $6000  
New Salary: $6500 

构造体零值

当定义了一个构造并且没有用任何值显式初始化它时,默认状况下会为该构造的字段调配零值。

package main

import (  
    "fmt"
)

type Employee struct {  
    firstName string
    lastName  string
    age       int
    salary    int
}

func main() {  
    var emp4 Employee //zero valued struct
    fmt.Println("First Name:", emp4.firstName)
    fmt.Println("Last Name:", emp4.lastName)
    fmt.Println("Age:", emp4.age)
    fmt.Println("Salary:", emp4.salary)
}

下面的程序定义了emp4,但没有用任何值初始化。因而,firstName和lastName被指定为字符串的零值,字符串为空字符串“”,age和salary被指定为零值int,即0。此程序打印

First Name:  
Last Name:  
Age: 0  
Salary: 0  

也能够为某些字段指定值,而疏忽其余字段。在这种状况下,被疏忽的字段被赋值为零。

package main

import (  
    "fmt"
)

type Employee struct {  
    firstName string
    lastName  string
    age       int
    salary    int
}

func main() {  
    emp5 := Employee{
        firstName: "John",
        lastName:  "Paul",
    }
    fmt.Println("First Name:", emp5.firstName)
    fmt.Println("Last Name:", emp5.lastName)
    fmt.Println("Age:", emp5.age)
    fmt.Println("Salary:", emp5.salary)
}

在下面的程序中。第16号和第17号,firstName和lastName被初始化,而年龄和薪水没有初始化。因而,年龄和工资被指定为零值。此程序输入:

First Name: John  
Last Name: Paul  
Age: 0  
Salary: 0  

构造体指针

也能够创立指向构造的指针。

package main

import (  
    "fmt"
)

type Employee struct {  
    firstName string
    lastName  string
    age       int
    salary    int
}

func main() {  
    emp8 := &Employee{
        firstName: "Sam",
        lastName:  "Anderson",
        age:       55,
        salary:    6000,
    }
    fmt.Println("First Name:", (*emp8).firstName)
    fmt.Println("Age:", (*emp8).age)
}

下面程序中的emp8是指向Employee构造的指针。(*emp8)。firstName是拜访emp8构造的firstName字段的语法。此程序打印:

First Name: Sam  
Age: 55 

Go语言为咱们提供了应用emp8.firstName而不是显式勾销援用(*emp8)的选项。firstName以拜访firstName字段。

package main

import (  
    "fmt"
)

type Employee struct {  
    firstName string
    lastName  string
    age       int
    salary    int
}

func main() {  
    emp8 := &Employee{
        firstName: "Sam",
        lastName:  "Anderson",
        age:       55,
        salary:    6000,
    }
    fmt.Println("First Name:", emp8.firstName)
    fmt.Println("Age:", emp8.age)
}

咱们曾经应用emp8.firstName拜访上述程序中的firstName字段,该程序还输入:

First Name: Sam  
Age: 55 

匿名字段

能够应用只蕴含类型而不蕴含字段名的字段创立构造。这类字段称为匿名字段。上面的代码段创立了一个struct Person,它有两个匿名字段string和int:

type Person struct {  
    string
    int
}

即便匿名字段没有显式名称,默认状况下,匿名字段的名称是其类型的名称。例如,在下面的Person构造中,尽管字段是匿名的,但默认状况下它们采纳字段类型的名称。所以Person构造有两个字段,别离是名称字符串和int。

package main

import (  
    "fmt"
)

type Person struct {  
    string
    int
}

func main() {  
    p1 := Person{
        string: "naveen",
        int:    50,
    }
    fmt.Println(p1.string)
    fmt.Println(p1.int)
}

在上述程序的第17行和第18行中,咱们拜访Person构造的匿名字段,应用它们的类型作为字段名,别离是string和int。上述程序的输入为:

naveen  
50 

构造体嵌套

构造可能蕴含字段,而字段又是构造。这些类型的构造称为嵌套构造。

package main

import (  
    "fmt"
)

type Address struct {  
    city  string
    state string
}

type Person struct {  
    name    string
    age     int
    address Address
}

func main() {  
    p := Person{
        name: "Naveen",
        age:  50,
        address: Address{
            city:  "Chicago",
            state: "Illinois",
        },
    }

    fmt.Println("Name:", p.name)
    fmt.Println("Age:", p.age)
    fmt.Println("City:", p.address.city)
    fmt.Println("State:", p.address.state)
}

上述程序中的Person构造具备字段地址,而字段地址又是一个构造。此程序打印:

Name: Naveen  
Age: 50  
City: Chicago  
State: Illinois

字段降级

属于构造中匿名构造字段的字段称为晋升字段,因为能够像拜访蕴含匿名构造字段构造一样拜访它们。我能够了解这个定义相当简单,所以让咱们深入研究一些代码来了解它。

type Address struct {  
    city string
    state string
}
type Person struct {  
    name string
    age  int
    Address
}

在下面的代码段中,Person构造有一个匿名字段Address,它是一个构造。当初,Address的字段,即city和state,被称为promoted字段,因为能够像间接在Person构造自身中申明一样拜访它们。

package main

import (  
    "fmt"
)

type Address struct {  
    city  string
    state string
}
type Person struct {  
    name string
    age  int
    Address
}

func main() {  
    p := Person{
        name: "Naveen",
        age:  50,
        Address: Address{
            city:  "Chicago",
            state: "Illinois",
        },
    }

    fmt.Println("Name:", p.name)
    fmt.Println("Age:", p.age)
    fmt.Println("City:", p.city)   //city is promoted field
    fmt.Println("State:", p.state) //state is promoted field
}

在下面程序的第29行和第30行中,能够拜访晋升字段city和state,就如同它们是应用语法p.city和p.state在构造p中申明的一样。此程序打印:

Name: Naveen  
Age: 50  
City: Chicago  
State: Illinois

构造体导出

如果构造类型以大写字母结尾,则它是导出类型,能够从其余包拜访。相似地,如果构造的字段以caps结尾,则能够从其余包拜访它们。让咱们编写一个具备自定义包的程序来更好地了解这一点。在Documents目录中创立名为structs的文件夹。请随便在任何您喜爱的中央创立它。我更喜爱我的文档目录。

mkdir ~/Documents/structs  

创立一个gomod,并命名为structs

cd ~/Documents/structs/  
go mod init structs

创立另外一个目录computer申明一个构造体。

mkdir computer  

创立一个spec.go文件,并写入如下内容:

package computer

type Spec struct { //exported struct  
    Maker string //exported field
    Price int //exported field
    model string //unexported field

}

下面的代码片段创立了一个程序包计算机,其中蕴含一个导出的构造类型Spec,其中有两个导出的字段Maker和Price,以及一个未导出的字段模型。让咱们从主包导入这个包并应用Spec构造。
创立名为main的文件。进入structs目录并在main.go中编写以下程序:

package main

import (  
    "structs/computer"
    "fmt"
)

func main() {  
    spec := computer.Spec {
            Maker: "apple",
            Price: 50000,
        }
    fmt.Println("Maker:", spec.Maker)
    fmt.Println("Price:", spec.Price)
}

这个构造体如下构造体:

├── structs
│   ├── computer
│   │   └── spec.go
│   ├── go.mod
│   └── main.go

在下面程序的第4行,咱们导入计算机包。在第13行和第14行,咱们拜访struct Spec的两个导出字段Maker和Price。这个程序能够通过执行命令go-install,而后执行structs命令来运行。

go install  
structs  

运行之后如下后果:

Maker: apple  
Price: 50000 

如果咱们试图拜访未报告的字段模型,编译器会埋怨。更换main的内容。应用以下代码。

package main

import (  
    "structs/computer"
    "fmt"
)

func main() {  
    spec := computer.Spec {
            Maker: "apple",
            Price: 50000,
            model: "Mac Mini",
        }
    fmt.Println("Maker:", spec.Maker)
    fmt.Println("Price:", spec.Price)
}

在上述程序的第12行中,咱们尝试拜访未报告的字段模型。运行此程序将导致编译谬误。

# structs
./main.go:12:13: unknown field 'model' in struct literal of type computer.Spec

因为模型字段未报告,因而无奈从其余包拜访它。

构造体比拟

构造是值类型,如果它们的每个字段都是可比拟的,则能够进行比拟。如果两个构造变量的对应字段相等,则认为它们相等。

package main

import (  
    "fmt"
)

type name struct {  
    firstName string
    lastName  string
}

func main() {  
    name1 := name{
        firstName: "Steve",
        lastName:  "Jobs",
    }
    name2 := name{
        firstName: "Steve",
        lastName:  "Jobs",
    }
    if name1 == name2 {
        fmt.Println("name1 and name2 are equal")
    } else {
        fmt.Println("name1 and name2 are not equal")
    }

    name3 := name{
        firstName: "Steve",
        lastName:  "Jobs",
    }
    name4 := name{
        firstName: "Steve",
    }

    if name3 == name4 {
        fmt.Println("name3 and name4 are equal")
    } else {
        fmt.Println("name3 and name4 are not equal")
    }
}

在下面的程序中,名称构造类型蕴含两个字符串字段。因为字符串是可比拟的,因而能够比拟类型名的两个构造变量。在下面的程序中,name1和name2相等,而name3和name4不相等。此程序将输入:

name1 and name2 are equal  
name3 and name4 are not equal 

如果构造变量蕴含不可比拟的字段,那么它们就不可比拟(感激reddit的alasija指出这一点)。

package main

import (  
    "fmt"
)

type image struct {  
    data map[int]int
}

func main() {  
    image1 := image{
        data: map[int]int{
            0: 155,
        }}
    image2 := image{
        data: map[int]int{
            0: 155,
        }}
    if image1 == image2 {
        fmt.Println("image1 and image2 are equal")
    }
}

在下面的程序中,图像构造类型蕴含类型映射的字段数据。地图是不可比拟的,因而无奈比拟image1和image2。如果运行此程序,编译将失败并返回谬误。

./prog.go:20:12: invalid operation: image1 == image2 (struct containing map[int]int cannot be compared)

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理