16、结构体 Structs

128 阅读3分钟

本文为译文 Structs

结构体是用户定义的类型。代表了一些类型的集合。

	type Employee struct {
		firstName string
		lastName  string
		age       int
	}

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

	/**
	  not recommended
	  Although the above syntax saves a few lines of code, it doesn't make the field declarations explicit. Please refrain from using the above syntax.
	*/
	type Employee struct {
		firstName, lastName string
		age                 int
	}

	/**
	not recommended
	creating struct without specifying field names
	Please refrain from using this syntax since it makes it difficult to figure  out which value is for which field
	*/
	emp2 := Employee{"Thomas", "Paul", 29, 800}

	//anonymous struct
	emp3 := struct {
		firstName string
		lastName  string
		age       int
		salary    int
	}{
		firstName: "Andreah",
		lastName:  "Nikola",
		age:       31,
		salary:    5000,
	}

结构体的零值

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(emp4)
	fmt.Println("First Name:", emp4.firstName)
	fmt.Println("Last Name:", emp4.lastName)
	fmt.Println("Age:", emp4.age)
	fmt.Println("Salary:", emp4.salary)
}


{  0 0}
First Name: 
Last Name: 
Age: 0
Salary: 0

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

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)

指向一个结构体

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)
}

go语言给我们了一个选项,可以使用emp8.firstName取代显示取值(*emp8).firstName来访问firstName字段。

匿名字段(anonymous fields)

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)
}

匿名字段的name就是类型的名字。

嵌套结构体(nested struct)

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)
}

提升字段(promoted fields)

**在结构体中的匿名结构体字段的字段属于提升字段。**是不是比较绕,看个例子就好了。

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
}

注意上面的代码,Pserson结构体有一个匿名字段Address,它是一个结构体。然后Address里面的字段citystate我们称之为promoted filed。因为他们可以被直接访问,就好像是Person结构体本身的字段一样。

可导出的结构体和字段

如果一个结构体类型是以大写开头的,那么它就可以被其他包访问。类似的如果一个结构体字段也是以大写开头的,它也可以被其他包访问。即认为是导出的。

我们写个demo理解一下

mkdir ~/Documents/structs  
cd ~/Documents/structs/  
go mod init structs  
mkdir computer  

Inside the computer directory, create a file spec.go with the following contents.

package computer

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

Create a file named main.go inside the structs directory and write the following program in 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

结构体相等比较(struct equality)

结构体是值类型。

如果他们的字段是可比较的,那么他们也是可比较的。

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 and name2 are equal  
name3 and name4 are not equal  

如果他们的字段类型是不可比较的,那么他们也是不可比较的。

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")
    }
}

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