Go Struct

struct

Go使用结构体和结构体成员来描述真实世界的实体和实例对应的各种属性。

Go中的类型可以被实例化,使用new或&构造的类型实例的类型是类型的指针。

结构体成员由一系列的成员变量构成,这些成员变量也被称为"字段"。

  • 字段拥有自己的类型和值;
  • 字段名必须唯一;
  • 字段的类型也可以是结构体,甚至是字段所在结构体的类型

Go的结构体与"类"都是符合结构体,但Go中结构体的内嵌配合接口比面向对象具有更高的扩展性和灵活性。

Go不仅结构体能拥有方法,且每种自定义类型也可以拥有自己的方法。

定义结构体

type 类型名struct {
字段1 字段1类型
字段2 字段2类型
...
}

实例化结构体————为结构体分配内存并初始化

结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正的分配内存。因此必须在定义结构体并实例化后才能使用结构体的字段。

实例化就是根据结构体定义的格式创建一份与格式一致的内存区域,结构体实例与实例间的内存是完全独立的。

基本的实例化形式

var ins T
# T 为结构体类型
#ins为结构体的实例

创建指针类型的结构体

Go可以使用new关键字对类型(包括结构体、整形、浮点型、字符串等)进行实例化,结构体在实例化后会形成指针类型的结构体。

ins := new(T)
# ins: T类型被实例化后保存到ins变量中,ins的类型为*T,属于指针。

Go可以像访问普通结构体一样使用"."访问结构体指针的成员。

type Player struct {
    Name string
    Health_Point int 
    Magic_Point int
}
tank := new(Player)
tank.Name = "Canon"
tank.Health_Point = 300

取结构体的地址实例化

ins := &T{}
# ins为结构体的实例,类型为*T,是指针类型

初始化结构体的成员变量

使用健值对初始化结构体

ins := 结构体类型名{
    字段1:字段1的值
    字段2:字段2的值
    ...
}

使用多个值的列表初始化结构体

ins := 结构体类型名{
    字段1的值,
    字段2的值,
}

初始化匿名结构体

匿名结构体没有类型名称,无须通过type关键字定义就可以直接使用。

ins := struct {
        // 匿名结构体字段定义
        字段1 字段类型1
        字段2 字段类型2
        ...
}{
        // 字段值初始化,可以不初始化
        初始化字段1: 字段1的值,
        初始化字段2:字段2的值,
        ...
}

实例

package main

import "fmt"


func main(){

	// 实例化一个匿名结构体
	msg := &struct{
		id int
		data string
	}{
		1024,
		"hello",
	}
	printMsg(msg)

}

// 接入匿名结构体,打印消息
func printMsg(msg *struct{
	id int
	data string
}) {
	fmt.Println("%T\n",msg)
}

匿名结构体在使用时需要重新定义,造成大量重复的代码,因此开发中较少使用。

构造函数————结构体和类型的一系列初始化操作的函数封装

Go的类型或结构体没有构造函数的功能。结构体的初始化过程可以使用函数封装实现。

多种方式创建和初始化结构体————模拟构造函数重载

结构体描述猫的特性。

type Cat struct {
        Color string
        Name  string
}

func NewCatByName(name string) *Cat {
    return &Cat{
        Name: name,
    }
}

func NewcatByColor(color string) *Cat {
    return &Cat{
        Color: color,
    }
}

带有父子关系结构体的构造和初始化————模拟父级构造调用

派生,继承

type Cat struct {
        Color string
        Name  string
}

type BlackCat struct {
        Cat                     // 嵌入Cat,类似派生
}

// 构造基类
fun NewCat(name string) *Cat {
     return &Cat{
        Name: name,
     }
}

// 构造子类
func NewBlackCat(color string) *BlackCat {
      cat := &BlcakCat{}
      cat.Color = color
      return cat
}

Go语言中没有提供构造函数相关的特殊机制,用户根据自己的需求,将参数使用函数传递到结构体构造参数中即可完成构造函数的任务。

类型嵌套和结构体嵌套

类型嵌套或匿名字段:结构体允许其成员字段再声明时没有字段名而只有类型

type Data struct {
        int 
        float32
        bool
}

ins := &Data{
       int: 10,
       float32: 3.14,
       bool: true,
}

类型内嵌仍然拥有自己的字段名,只是字段名就是其类型本身。结构体要求字段名称必须唯一,因此一个结构体中同种类型的匿名字段只有一个。

结构体实例化后,如果匿名的字段类型为结构体,可直接访问匿名结构体里的所有成员,这种方式被称为结构体内嵌。

声明结构体内嵌

type BasicColor struct {
      R, G, B float32
}

type Color struct {
     BasicColor
     Alpha float32
}

func main() {
     var c Color
     c.R = 1
     c.G = 1
     c.B = 0
     c.Alpha = 1
     fmt.Printf("%+v",c)
}

将Basic Color结构体嵌入到Color结构体中,Basic Color没有字段名而只有类型,这种写法就叫做结构体内嵌

结构内嵌特性

  • 内嵌的结构体可以直接访问其成员变量
  • 内嵌结构体的字段名是它的类型名

面向对象——继承

// 可飞行
type Flying struct{}

func (f *Walkable) Fly() {
    fmt.Println("can fly")
}

// 可行走
type Walkable struct{}

func (f *Walkable) Walk() {
    fmt.Println("can walk")
}

// 人类
type Human struct {
   Walkable
}

// 鸟类 
type Bird struct {
    Walkable                    // 可走
    Flying                      // 可飞行
}

func main() {
        b := new(Bird)
        b.Fly()
        b.Walk()
}

使用Go语言的内嵌结构体实现对象特性,可以自由地在对象中增、删、改各种特性。

初始化结构体内嵌

结构体内嵌初始化时,将结构体内嵌的类型作为字段名像普通结构体一样进行初始化

// 车轮
type Wheel struct {
        Size int
}

// 引擎
type Engine struct {
        Power int       // 功率
        Type string     // 类型
}

// 车
type Car struct {
        Wheel
        Engine
}

func main() {
        c := Car{
                Wheel: Wheel{
                        Size: 18,
                },
                Engine: Engine{
                        Type: "1.4T",
                        Power: 1.43,
                }
        }
        fmt.Println("%+v\n",c)
}

使用场景

使用结构题体解析JSON数据

// 获取http内容
	url := "https://xxxxxxxx"
	resg, err := http.Get(url)
	defer resg.Body.Close()
	if err!=nil {
        panic(fmt.Sprintf("err: %q",err))
    }
	if( resg.StatusCode!=200 ){
		Checkerr(errors.New("请求失败"))
	}
	msg, err := ioutil.ReadAll(resg.Body)
	if err!=nil {
    	panic(fmt.Sprintf("err: %q",err))
    }
	var m Message
    err1 := json.Unmarshal(msg,&m)
    if err1!=nil {
        panic(fmt.Sprintf("err: %q",err))
    }
    
    type Message struct {
    	Data struct {
    		List []struct {
    			ImageID          string `json:"image_id"`
    			Width            int    `json:"width"`
    			Height           int    `json:"height"`
    			FileSize         int    `json:"file_size"`
    			Type             string `json:"type"`
    			Signature        string `json:"signature"`
    			SourceType       string `json:"source_type"`
    			SourceSignature  string `json:"source_signature"`
    			PreviewURL       string `json:"preview_url"`
    			CreatedTime      int    `json:"created_time"`
    			LastModifiedTime int    `json:"last_modified_time"`
    		} `json:"list"`
    		PageInfo struct {
    			Page        int `json:"page"`
    			PageSize    int `json:"page_size"`
    			TotalNumber int `json:"total_number"`
    			TotalPage   int `json:"total_page"`
    		} `json:"page_info"`
    	} `json:"data"`
    	Code    int    `json:"code"`
    	Message string `json:"message"`
    }

解析接口数据:https://mholt.github.io/json-to-go/

posted @ 2020-02-24 21:29  walkingSun  阅读(327)  评论(0编辑  收藏  举报
**/