1. 前言

在大一学C语言时我们就接触过结构体,go语言中同样也有结构体,并在日常项目中发挥着重要作用。go语言中没有类的感念概念,也不支持“类”的继承等面向对象的概念,结构体和接口方法配合使用更具灵活性。

结构体中字段大写开头表示可公开访问,小写表示私有(仅在定义当前结构体的包中可访问)。

2. 结构体的定义

使用关键字 type、struct:

// 定义Person 为用户struct类型
type Person struct {
    Name  string
    Address string
    Age     int
}

同类型的字段也可以写在一行

type Person struct {
    Name, Address string
    Age     int
}

3. 声明结构体类型的变量

当声明了结构体类型就可以使用这个类型创建值。

使用结构类型声明变量,并初始化为零值:

var variable_name Person

使用结构体字面量声明变量,并初始化为非零值

// 声明 Person 类型的变量,并初始化所有字段
variable_name := Person{
    Name: "雨中笑",
    Address: “yzx-fjl.cn”,
    Age: 1,
}

某些字段没有初始值的时候,该字段可不写。没有指定初始值的字段的值就是该字段类型的零值

使用值的列表初始化

variable_name := Person{
    "雨中笑",
    “yzx-fjl.cn”,
    1,
}

这种方式初始化需要初始化结构体的所有字段、填充顺序需要一致

结构体也是值类型,因此可以通过 new 函数来创建:

variable_name := new(Person)

new 函数的特点是只能把内存初始化为零值并返回其指针

对结构体指针进行键值对初始化

使用&对结构体进行取地址

variable_name := &Person{}

相当于对该结构体类型进行了一次new实例化操作。

4. 类型别名

如Mysql的别名是MysqlDB

var MysqlDB *Mysql

type Mysql struct {
    conn *gorm.DB
}

5. 匿名字段

结构体可以包含一个或多个匿名字段,但同型的匿名字段只能有一个,匿名字段默认采用类型名作为字段名。

package main

import "fmt"

type Person struct {
    name string
    string
    int // 匿名字段
}

func main() {
    p := Person{"雨中笑","匿名字段",20,}
    fmt.Printf("%#v\n", p)        //输出:main.Person{string:"雨中笑", string:"匿名字段", int:20}
    fmt.Println(p.string, p.int) //输出:雨中笑 匿名字段
}

6. 内嵌结构体

结构体也是一种数据类型,所以它同样可以作为匿名字段使用:

type Person struct {
    Name  string
    Age     int
    Address string
}

type Student struct {
    ID int
    Person
}

下面的代码可以声明并初始化 Student 类型的变量:

st := Student {
StudentID: 1,
Person:    Person{"雨中笑", 1, "yzx-fjl.cn"},
}

当遇到内嵌结构体存在相同的字段名时,指定具体的内嵌结构体的字段就可,如:


type Person struct {
    Name  string
    Age     int
    Address string
}

type Teacher struct {
    Name  string
    Age     int
    Address string
}

type Student struct {
    ID int
    Person
    Teacher
}

func main() {
var student Student

student.Person.Name = "person名"
student.Teacher.Name = "teacher名"
}

7. 结构体作为函数参数

package main

import "fmt"

type Person struct {
    Name  string
    Age     int
    Address string
}

func main() {
    printPerson(Person{Name: "你好"})     //输出:Person name : 你好 
    printPerson1(&Person{Name: "雨中笑"}) //输出:Person1 name : 雨中笑
}

// 用结构体做参数
func printPerson(person Person) {
    fmt.Printf("Person name : %s\n", person.Name)
}

// 用结构体指针类型做参数
func printPerson1(person *Person) {
    fmt.Printf("Person1 name : %s\n", person.Name)
}

一般结构体比较复杂的话,值拷贝性能开销会比较大。

8. 结构体作为函数返回值

package main

import "fmt"

type Person struct {
    Name  string
    Age     int
    Address string
}

func main() {
    person := printPerson()
    person1 := printPerson1()

    fmt.Println(person.Name)
    fmt.Println(person1.Name)
}

// 用结构体做返回值
func printPerson() Person {
    return Person{Name: "你好"}
}

// 用结构体指针类型做返回值
func printPerson1() *Person {
    return &Person{Name: "雨中笑"}
}

输出:

你好
雨中笑

9. 结构体与JSON

接收和传送数据时,有时会对结构体做json处理,Go语言自带的json包可以方便的 JSON 读取和写入 JSON 数据

json.Marshal(v interface{}) 将传入的结构体生成JSON数据

json.Unmarshal(data []byte, v interface{}) 将JSON解组到结构中,解组匹配传入对象

package main

import (
    "encoding/json"
    "fmt"
)

type Info struct {
    Srcid string `json:"srcid"`
    Location string `json:"location"`
}

type Ip struct {
    Srcid     string
    QueryID   string
    Data      []*Info
    ResultNum string
}

func main() {
    body := Ip{
        Srcid: "5809",
        QueryID: "2610195558",
        ResultNum: "1",
        Data:make([]*Info, 0, 1),
    }

    body.Data = append(body.Data, &Info{Location: "广东省 移动"})

    //JSON序列化:结构体-->JSON格式的字符串
    data, err := json.Marshal(body)
    if err != nil {
        fmt.Println("json marshal failed")
        return
    }
    fmt.Printf("json:%s\n", data)

    //JSON反序列化:JSON格式的字符串-->结构体
    str := `{"Srcid": "5809","QueryID": "2610195558","Data": [{"srcid": "5809","location": "广东省 移动"}],"ResultNum": "1"}`

    ipList := &Ip{}
    err = json.Unmarshal([]byte(str), ipList)
    if err != nil {
        fmt.Println("json unmarshal failed!")
        return
    }
    fmt.Printf("%#v\n", ipList)
}

输出:

json:{"Srcid":"5809","QueryID":"2610195558","Data":[{"srcid":"","location":"广东省 移动"}],"ResultNum":"1"}
&main.Ip{Srcid:"5809", QueryID:"2610195558", Data:[]*main.Info{(*main.Info)(0x11004210)}, ResultNum:"1"}

10. 获取外部接口数据解析

这里写一个例子,通过访问IP接口获得数据,再经行解析使用

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
)

type Info struct {
    Srcid string `json:"srcid"`  //指定tag实现json序列化该字段时的key
    Location string `json:"location"`
}

type Ip struct {
    Srcid     string
    QueryID   string
    Data      []Info
    ResultNum string
}

func main() {
    ip := "117.136.31.45"
    addr := fmt.Sprintf("https://sp1.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query=%s&resource_id=5809", ip)
    resp, err := http.Get(addr)
    if err != nil {
        // handle error
    }

    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        // handle error
    }

    fmt.Println(string(body))

    var ipList Ip
    err = json.Unmarshal(body, &ipList)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println(ipList)
    fmt.Println(ip, "地址:", ipList.Data[0].Location)
}

输出:

{"Srcid":"5809","ResultCode":"0","status":"0","QueryID":"3329069979","Result":[{"DisplayData":{"strategy":{"tempName":"ip","precharge":"0","ctplOrPhp":"1"},"resultData":{"tplData":{"srcid":"5809","resourceid":"5809","OriginQuery":"117.136.31.45","origipquery":"117.136.31.45","query":"117.136.31.45","origip":"117.136.31.45","location":"\u5e7f\u4e1c\u7701 \u79fb\u52a8","userip":"","showlamp":"1","tplt":"ip","titlecont":"IP\u5730\u5740\u67e5\u8be2","realurl":"http:\/\/www.ip138.com\/","showLikeShare":"1","shareImage":"1","data_source":"AE"},"extData":{"tplt":"ip","resourceid":"5809","OriginQuery":"117.136.31.45"}}},"ResultURL":"http:\/\/www.ip138.com\/","Weight":"2","Sort":"1","SrcID":"5809","ClickNeed":"0","SubResult":[],"SubResNum":"0","ar_passthrough":[],"RecoverCacheTime":"0"}],"data":[{"srcid":"5809","resourceid":"5809","OriginQuery":"117.136.31.45","origipquery":"117.136.31.45","query":"117.136.31.45","origip":"117.136.31.45","location":"\u5e7f\u4e1c\u7701 \u79fb\u52a8","userip":"","showlamp":"1","tplt":"ip","titlecont":"IP\u5730\u5740\u67e5\u8be2","realurl":"http:\/\/www.ip138.com\/","showLikeShare":"1","shareImage":"1"}],"ResultNum":"1"}
{5809 3329069979 [{5809 广东省 移动}] 1}
117.136.31.45 地址: 广东省 移动
Copyright © yzx该文章修订时间: 2021-11-03 15:39:17

results matching ""

    No results matching ""