zoukankan      html  css  js  c++  java
  • Go 结构体的使用

    结构体是用户定义的类型,表示若干个字段(Field)的集合。有时应该把数据整合在一起,而不是让这些数据没有联系。这种情况下可以使用结构体。

    例如,一个职员有 firstNamelastName 和 age 三个属性,而把这些属性组合在一个结构体 employee 中就很合理。

    结构体的声明基础

    type Employee struct {
        firstName string
        lastName  string
        age       int
    }
    

     在上面的代码片段里,声明了一个结构体类型 Employee,它有 firstNamelastName 和 age 三个字段。通过把相同类型的字段声明在同一行,结构体可以变得更加紧凑。在上面的结构体中,firstName 和 lastName 属于相同的 string 类型,于是这个结构体可以重写为: 

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

    上面的结构体 Employee 称为 命名的结构体(Named Structure)。我们创建了名为 Employee 的新类型,而它可以用于创建 Employee 类型的结构体变量。

    声明结构体时也可以不用声明一个新类型,这样的结构体类型称为 匿名结构体(Anonymous Structure)。

    var employee struct {
        firstName, lastName string
        age int
    }
    

    上述代码片段创建一个匿名结构体 employee 。  

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

     上述代码片段通过匿名结构体 创建了一个结构体变量 。 

    结构体基础使用

    • 结构体变量初始化
    • 结构体指针变量初始化
    • 结构体变量之间的比较与赋值
    • 在函数中传递结构体变量与结构体指针变量
    • 定义结构体函数成员与调用
    package main
    
    import (
    	"fmt"
    )
    //结构体为类型定义
    //创建一个结构体,四个数据属性,四个函数属性
    /////////////////////////////////////
    type Person struct {
    		name string
    		age int
    		sex bool
    		//hobby []string
    }
    
    //*Person意味传递是真实地址
    func (p *Person)Eat(){
    	fmt.Printf("%s爱吃西红柿炒鸡蛋
    ",p.name)
    }
    func (p *Person)Drink(){
    	fmt.Printf("%s爱喝可乐
    ",p.name)
    }
    func (p *Person)Sleep(){
    	fmt.Printf("%s要睡8个小时
    ",p.name)
    }
    func (p *Person)Love(){
    	fmt.Printf("%s喜欢
    ",p.name)
    }
    ////////////////////////////////////////////
    
    //值传递与属性传递
    ////////////////////////
    func MakeHimLove(p Person){p.Love()}
    
    func MakeHisPtrLove(p *Person){p.Love()}
    /////////////////////
    
    func main(){
    
    
    //////结构体变量初始化///////////////
    	//顺序初始化:创建对象时按顺序给所有属性赋值
    	p1 := Person{"lili",8,true}
    	fmt.Println(p1)
    	//指定成员初始化:指定成员变量进行赋值,没有指定的成员变量为默认值
    	p2 := Person{name:"mingming",sex:true} //--未初始化的成员变量,取该数据类型的默认值。
    	fmt.Println(p2)
    	//创建后初始化:
    	p3 := Person{} //--未初始化的成员变量,取该数据类型的默认值。
    	p3.name ="xiaoli"
    	p3.age =19
    	fmt.Println(p3)
    ////////////////////////
    
    
    ///////////结构体指针变量初始化/////////////
    
    	//一般初始化
    	var p4 *Person = &Person{"weiai",26,true}
    	fmt.Println(p4)
    
    	//使用new初始化
    	p5 := new(Person)
    	p5.name ="titi"
    	p5.age =31
    	p5.sex =false
    	//注意:在64位操作系统下,所有类型的指针,均为8个字节
    ////////////////////////
    
    ///////////结构体变量的比较和赋值/////////////
    //1.比较:只能使用 ==和!=   不能使用 > < >=  <=
    //注意:结构体有些类型存在,结构体变量是不能进行比较的,如:[]string
    //结构体是值类型。如果它的每一个字段都是可比较的,则该结构体也是可比较的。如果两个结构体变量的对应字段相等,则这两个变量也是相等的。 fmt.Println("p1 == p2:",p1 == p2) //2.赋值:相同类型结构体可以直接赋值 var temp Person temp = p1 fmt.Println(temp) //////////////////////// ////////////函数内部使用结构体传参///////////// //值传递传递的是副本,引用传递传递的才是本身 //注意:值传递内存消耗大,效率低 //unasfe.Sizeof(变量名):查看变量所占的内存空间大小 //要求传递值就必须传递值 //MakeHimLove(p1) //要求传递指针就必须传递指针:地址传递、引用传递 //结构体变量的地址为结构体首个元素的地址 //MakeHisPtrLove(&p1) ///////////////////// ////////////结构体调用自身函数////////////////// ///////////////////// // //实例调用方法 // p1.Eat() // p1.Drink() // p1.Sleep() // p1.Love() ///////////////////////////////////////////// }

      

      

    补充知识点

    • 匿名字段
    • 嵌套结构体(Nested Structs)
    • 提升字段(Promoted Fields)
    • 导出结构体和字段

    匿名字段

    当我们创建结构体时,字段可以只有类型,而没有字段名。这样的字段称为匿名字段(Anonymous Field)。

    以下代码中有 Person 结构体,它含有两个匿名字段 string 和 int

    package main
    
    import (  
        "fmt"
    )
    type Person struct {  
        string
        int
    }
    
    func main() {  
        p := Person{"Naveen", 50}
        fmt.Println(p)
    }

    该程序输出 {Naveen 50}

    虽然匿名字段没有名称,但其实匿名字段的名称就默认为它的类型。比如在上面的 Person 结构体里,虽说字段是匿名的,但 Go 默认这些字段名是它们各自的类型。所以 Person 结构体有两个名为 string 和 int 的字段。

     

    嵌套结构体(Nested Structs)

    结构体的字段有可能也是一个结构体。这样的结构体称为嵌套结构体。

    package main
    
    import (  
        "fmt"
    )
    
    type Address struct {  
        city, state string
    }
    type Person struct {  
        name string
        age int
        address Address
    }
    
    func main() {  
        var p Person
        p.name = "Naveen"
        p.age = 50
        p.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 有一个字段 address,而 address 也是结构体。该程序输出:

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

      

    提升字段(Promoted Fields)

    如果是结构体中有匿名的结构体类型字段,则该匿名结构体里的字段就称为提升字段。这是因为提升字段就像是属于外部结构体一样,可以用外部结构体直接访问。我知道这种定义很复杂,所以我们直接研究下代码来理解吧。

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

    在上面的代码片段中,Person 结构体有一个匿名字段 Address,而 Address 是一个结构体。现在结构体 Address 有 city 和 state 两个字段,访问这两个字段就像在 Person 里直接声明的一样,因此我们称之为提升字段。

    package main
    
    import (
        "fmt"
    )
    
    type Address struct {
        city, state string
    }
    type Person struct {
        name string
        age  int
        Address
    }
    
    func main() {  
        var p Person
        p.name = "Naveen"
        p.age = 50
        p.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
    }

    在上面代码中的第 26 行和第 27 行,我们使用了语法 p.city 和 p.state,访问提升字段 city 和 state 就像它们是在结构体 p 中声明的一样。该程序会输出:

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

      

    导出结构体和字段

    如果结构体名称以大写字母开头,则它是其他包可以访问的导出类型(Exported Type)。同样,如果结构体里的字段首字母大写,它也能被其他包访问到。

    让我们使用自定义包,编写一个程序来更好地去理解它。

    在你的 Go 工作区的 src 目录中,创建一个名为 structs 的文件夹。另外在 structs 中再创建一个目录 computer

    在 computer 目录中,在名为 spec.go 的文件中保存下面的程序。

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

    上面的代码片段中,创建了一个 computer 包,里面有一个导出结构体类型 SpecSpec 有两个导出字段 Maker 和 Price,和一个未导出的字段 model。接下来我们会在 main 包中导入这个包,并使用 Spec 结构体。

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

    包结构如下所示:

    src  
       structs
            computer
                spec.go
            main.go

    在上述程序的第 3 行,我们导入了 computer 包。在第 8 行和第 9 行,我们访问了结构体 Spec 的两个导出字段 Maker 和 Price。执行命令 go install structs 和 workspacepath/bin/structs,运行该程序。

    如果我们试图访问未导出的字段 model,编译器会报错。将 main.go 的内容替换为下面的代码。

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

    在上面程序的第 10 行,我们试图访问未导出的字段 model。如果运行这个程序,编译器会产生错误:spec.model undefined (cannot refer to unexported field or method model)

    refer:『GCTT 出品』Go 系列教程 —— 第 16 部分:结构体

  • 相关阅读:
    MyEclipse 2015反编译插件安装
    RocketMQ事务消费和顺序消费详解
    Rocket重试机制,消息模式,刷盘方式
    前端js上传文件 到后端接收文件
    Junit进行单元测试
    json简单使用
    valgrind的使用--检测内存
    使用scrapy框架爬取自己的博文(3)
    使用scrapy框架爬取自己的博文
    Scrapy下xpath基本的使用方法
  • 原文地址:https://www.cnblogs.com/-wenli/p/11783529.html
Copyright © 2011-2022 走看看