GO Struct Ultra-подробное объяснение

Go

Оригинальный автор, публичный аккаунт [программист чтение], прошу обратить внимание на паблик-аккаунт, просьба указывать источник перепечатываемой статьи.

Язык Go обеспечивает поддержку структур,struct, китайский перевод называется结构体, как и массивы, является составным типом, а не ссылочным типом.

Конструкция языка Go, аналогично структуре или другому языку на объектно-ориентированном языке программирования на языке C, может определить поля (атрибуты) и методы, но есть также разные места, должны изучать углубленное обучение, может различать им разница.

Обратите внимание на разницу между составными и ссылочными типами, которая также должна быть разницей между передачей по значению и передачей по ссылке.

определение

Используйте ключевое слово struct для определения структуры, членов структуры, называемых полями или свойствами структуры.

type Member struct {
    id          int
    name, email string
    gender, age int
}

В приведенном выше коде мы определяем структуру с 5 полями, как видите, одного типаnameиemail,genderиageОпределяется в той же линии, но лучшая практика программирования состоит в том, чтобы определить только одно поле на линию, например:

type Member struct {
    id     int
    name   string
    email  string
    gender int
    age    int
}

Конечно, структура также может содержать любые поля, называемые空结构体, struct{} представляет собой пустую структуру, обратите внимание, что нет смысла определять пустую структуру напрямую, но в параллельном программировании связь между каналами может использовать struct{} в качестве семафора.

ch := make(chan struct{})
ch <- struct{}{}

использовать

В приведенном выше примере мы определили тип структуры Member, а затем можем создавать переменные этого пользовательского типа.

Определите переменные напрямую.Этот метод использования не присваивает начальные значения полям, поэтому всем полям будут автоматически присвоены нулевые значения их собственных типов, таких какnameЗначением является пустая строка "", а значение возраста равно 0.

var m1 Member//所有字段均为空值

Используйте литералы для создания переменных.Таким образом, вы можете присваивать начальные значения членам структуры в фигурных скобках.Существует два способа присвоения начальных значений.Один из них заключается в присвоении значений в порядке полей в структуре , В следующем кодеm2Используется этот метод, который требует, чтобы всем полям были присвоены значения, поэтому, если полей слишком много, будет очень громоздко присваивать значения каждому полю переменной.m3Созданный таким образом, для других полей, которые не указаны, в качестве значения инициализации используется нулевое значение типа поля.

var m2 = Member{1,"小明","xiaoming@163.com",1,18} // 简短变量声明方式:m2 := Member{1,"小明","xiaoming@163.com",1,18}
var m3 = Member{id:2,"name":"小红"}// 简短变量声明方式:m3 := Member{id:2,"name":"小红"}

поле доступа

В имени переменной используйте запятые(.), вы можете получить доступ к полям в типе структуры, или присвоить значения полям, или выполнить адресные (&) операции над полями.

fmt.Println(m2.name)//输出:小明
m3.name = "小花"
fmt.Println(m3.name)//输出:小花

age := &m3.age
*age = 20
fmt.Println(m3.age)//20

структура указателя

Как и массивы, структуры передаются по значению. Например, когда массив или структура передаются в качестве фактического параметра формальному параметру функции, будет сделана копия. Поэтому для повышения производительности массив обычно не передается непосредственно в функцию, но вместо использования слайсов (ссылочных типов) при передаче структур в функции можно использовать指针结构体.

Структура указателя, то есть указатель на структуру.При объявлении структурной переменной необходимо добавить знак * перед типом структуры, чтобы объявить указатель на структуру, например:

Обратите внимание, что тип указателя является ссылочным типом.При объявлении указателя структуры, если он не инициализирован, начальное значение равно nil.Только после инициализации можно получить доступ к полю или присвоить ему значение.

var m1 *Member
m1.name = "小明"//错误用法,未初始化,m1为nil

m1 = &Member{}
m1.name = "小明"//初始化后,结构体指针指向某个结构体地址,才能访问字段,为字段赋值。 

Кроме того, используя встроенную новую () функцию Go, вы можете выделить память для инициализации структуры и вернуть указатель на выделенную память. Поскольку он был инициализирован, вы можете напрямую доступ к полям.

var m2 = new(Member)
m2.name = "小红"

Мы знаем, что, если структура передана функции, но структура реплики, если измененное поле структуры внутри функции, вне структуры не будет затронуто, а если структура указывает на функцию, то на средства для использование функции для изменения созданной структуры повлияет на структуру указателя.

func main() {
    m1 := Member{}
    m2 := new(Member)
    Change(m1,m2)
    fmt.Println(m1,m2)
}

func Change(m1 Member,m2 *Member){
    m1.Name = "小明"
    m2.Name = "小红"
}

видимость

В приведенном выше примере мы определяем имена полей структуры как строчные, что означает, что эти поля находятся в包外不可见, и, следовательно, к ним нельзя получить доступ в других пакетах, разрешен только внутри пакета.

В следующем примере мы объявляем Member в пакете member, а затем создаем переменную в основном пакете, но так как поля структуры не видны вне пакета, мы не можем присвоить полям начальные значения, и мы не может присвоить значения по полю или индексу, выдаст ошибку паники.

package member
type Member struct {
    id     int
    name   string
    email  string
    gender int
    age    int
}

package main

fun main(){
    var m = member.Member{1,"小明","xiaoming@163.com",1,18}//会引发panic错误
}

Поэтому, если вы хотите получить доступ к полям структуры в другом пакете в одном пакете, это должна быть переменная, начинающаяся с заглавной буквы, которую можно экспортировать, например:

type Member struct {
    Id     int
    Name   string
    Email  string
    Gender int
    Age    int
}

Tags

При определении поля структуры, в дополнение к названию поля и типа данных, вы также можете использовать BackTicks, чтобы объявить метаинформацию для поля структуры. Эта метаинформация называется тегом и используется для ассоциирования его с полем во время компиляции Фаза. Например, мы будем использовать приведенный выше примера структуру в изменении:

type Member struct {
    Id     int    `json:"id,-"`
    Name   string `json:"name"`
    Email  string `json:"email"`
    Gender int    `json:"gender,"`
    Age    int    `json:"age"`
}

В приведенном выше примере демонстрируется информация тега, используемая при кодировании или декодировании структуры с помощью пакета encoding/json.

Тег состоит из ряда пар ключ-значение ключ: "значение", разделенных пробелами и заключенных в обратные кавычки, например:

Id int `json:"id" gorm:"AUTO_INCREMENT"`

характеристика

Ниже приводится сводка соответствующих характеристик нескольких структур:

передать по значению

Как и массив, структура является составным типом.Передается ли она в качестве фактического параметра функции или присваивается другим переменным, она передается по значению, т. е. дублируется.

нет наследства

Перейти на поддержку объектно-ориентированного языка программирования, но нет понятия наследования, в структуре можно создавать более сложные структуры, комбинируя другие структуры.

Структура не может содержать себя

Структура не содержит себя.Например, поля в Member не могут иметь тип Member, но могут быть *Member.

метод

В языке Go, если функция привязана к определенному типу, функция называется методом этого типа, а метод определяется путем добавления переменной определенного типа между func и именем функции.Эта переменная типа называется方法接收器,как:

Обратите внимание, что не только структуры могут связывать методы, любой тип может связывать методы, но здесь мы вводим методы связывания со структурами.

func setName(m Member,name string){//普通函数
    m.Name = name
}

func (m Member)setName(name string){//绑定到Member结构体的方法
    m.Name = name
}

Из приведенного выше примера мы можем видеть, что по方法接收器Вы можете получить доступ к полям структуры, которая похожа на ключевое слово this в других языках программирования, но в языке Go это просто имя переменной, мы можем называть ее произвольно.方法接收器.

Вызов метода для структуры аналогичен вызову поля:

m := Member{}
m.setName("小明")
fmt.Println(m.Name)//输出为空

В приведенном выше коде нам будет очень странно, не устанавливается ли значение поля Name вызовом метода setName()? Почему вывод все еще пуст?

Это потому, что структура передается по значению. Когда мы вызываем setName, получатель метода получает только копию переменной структуры. Значение восстанавливается через копию и не влияет на вызывающую сторону. Поэтому мы можем использовать метод для приемник определяется как переменная-указатель, и цель изменения структуры может быть достигнута.

func (m *Member)setName(name string){/将Member改为*Member
    m.Name = name
}

m := Member{}
m.setName("小明")
fmt.Println(m.Name)//小明

Метод тот же, что и у поля.Если первая буква строчная, она может быть видна только в пакете и недоступна в других пакетах.Поэтому, если вы хотите получить к ней доступ в других пакетахsetName, имя метода должно быть изменено наSetName.

комбинация

Мы знаем, что в структуре нет понятия наследования.На самом деле в языке Go нет понятия наследования.В философии программирования языка Go рекомендуется использовать组合способ добиться эффекта повторного использования кода.

что такое комбинация

Комбинацию можно понимать как определение структуры, поля которой могут быть другими структурами, так что разные структуры могут совместно использовать одни и те же поля.

Обратите внимание, что, помня о том, что мы упоминали ранее, структуры не могут содержать сами себя, но могут содержать указатели на структуры.

Например, мы определяем структуру с именем Animal для представления животных, если мы хотим определить структуру для представления кошек, например:

type Animal struct {
    Name   string  //名称
    Color  string  //颜色
    Height float32 //身高
    Weight float32 //体重
    Age    int     //年龄
}
//奔跑
func (a Animal)Run() {
    fmt.Println(a.Name + "is running")
}
//吃东西
func (a Animal)Eat() {
    fmt.Println(a.Name + "is eating")
}

type Cat struct {
    a Animal
}

func main() {
    var c = Cat{
	    a: Animal{
            Name:   "猫猫",
            Color:  "橙色",
            Weight: 10,
            Height: 30,
            Age:    5,
        },
    }
    fmt.Println(c.a.Name)
    c.a.Run()
}

Как видите, когда мы определяем структуру Cat, мы можем использовать структуру Animal как поле Cat.

анонимное поле

В приведенном выше примере мы видим, что когда структура Animal используется в качестве поля Cat, ее имя переменной — a, поэтому, когда мы обращаемся к методу Animal, синтаксис такой:c.a.Run(), метод и использование поля для доступа к типу поля через листовой атрибут очень громоздки.

Язык Go поддерживает прямое использование типа в качестве поля структуры без использования имени переменной.Такой тип поля называется匿名字段,как:

type Lion struct {
	Animal //匿名字段
}

func main(){
    var lion = Lion{
        Animal{
            Name:  "小狮子",
            Color: "灰色",
        },
    }
    lion.Run()
    fmt.Println(lion.Name)
}

Из вышеприведенного примера видно, что когда вы объединяете другие типы через анонимные поля, а затем получаете доступ к методам и полям анонимных типов полей, вам не нужно использовать листовые атрибуты, что очень удобно.

резюме

В программировании на языке Go структура, вероятно, является наиболее часто используемым типом данных.Определяя структуры с различными полями и методами и абстрактно комбинируя различные структуры, это, вероятно, объектно-ориентированное программирование на языке Go.


Ваше внимание — самое большое поощрение на моем писательском пути!