结构体是类型中带有成员的复合类型。go语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性。

go语言中的类型可以被实例化,使用new和&构造类型实例的类型是类型的指针。

结构体成员是由一系列成员变量构成,成员(字段)有以下属性:

  • 字段名称唯一;
  • 拥有类型和值;
  • 成员的类型可以是结构体,甚至是字段所在结构体的类型。

go不支持”类“的概念,也不支持"继承"面向对象的概念。

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

在函数外部定义结构体,作用域是全局的。

结构体基础

定义结构体

type 结构体名称 struct {
字段名 字段类型
...
}
  • 结构体类型名在包内不能重复

示例,表示直角坐标系中的点的坐标

type Point struct {
X int
Y int
}

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

结构体定义只是一种内存布局的描述,只有结构化后才能真正分配内存。

基本的实例化形式

示例,表示直角坐标系中的点的坐标

type Point struct {
X int
Y int
} var p Point
p.x = 10
p.y = 20

创建指针类型的结构体

使用new关键字对类型进行实例化,会形成指针类型的结构体。

type Player struct {
Name string
HealthPoint int
MagicPoint int
} tank := new(Player)
tank.name = "Canon"
tank.HealthPoint = 300

go 语言中访问成员变量可以继续使用”.“,go增加了语法糖,将ins.Name转化为(*ins).Name

取结构体地址实例化

对结构体进行&取地址,视为对该类型进行一次new实例化操作。

ins := &T{}
  • T表示结构体类型
  • Ins 为结构体实例,类型是*T

示例,定义一个命令行指令,指令包含名臣,关联变量和注释

type Command struct {
Name string
Var *int // 此处使用指针,可以随时与绑定的值保持同步
Comment string
} var version int = 1
cmd := &Command{}
cmd.Name = "version"
cmd.Var = &version
cmd.Comment = "show version"

初始化结构体成员变量

使用基本形式初始化结构体

示例,颜色的RGB值

type Color struct {
R, G, B byte
}

使用键值对初始化结构体

示例,描述家庭任务关联

type People struct {
name string
child *People
} relationship := &People{
name: "grand father",
child: &People{
name: "Dad",
child: &People{
name: "I",
},
},
}
fmt.Println(relationship.child.child.name)

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

注意

  • 必须初始化结构体的所有字段
  • 初始值与字段顺序保持一致
  • 键值对与值列表的形式不能混用

示例,地址

type Address struct {
Privince string
City string
ZipCode int
PhoneNumber string
} addr := Address{
"上海",
"上海",
"222300",
"0"
}

构造函数--结构体初始化的函数封装

go语言或者结构体没有构造函数的功能,结构体的初始化的过程可以用函数封装实现。

模拟构造函数重载

示例,根据颜色和名称可以构造不同猫的实例。

type Cat struct {
Name string
COlor string
} func NewCatByName(name string) *Cat {
return &Cat{
Name: name,
}
} func NewCatByColor(color string) *Cat {
return &Cat{
Color: color,
}
}

模拟父级构造调用

示例,黑猫是一种猫,猫是黑猫的泛称。

package main

import "fmt"

type Cat struct {
Name string
Color string
} type BlackCat struct {
Cat // 嵌入Cat,类似于派生
} func NewCat(name string) *Cat {
return &Cat{
Name: name,
}
} func NewBlackCat(name string) *BlackCat {
cat := &BlackCat{}
cat.Color = "black"
cat.Name = name
return cat
} func main() {
cat := NewCat("wow")
fmt.Println(cat)
blackcat := NewBlackCat("hello")
fmt.Println(blackcat)
}

方法

使用背包作为"对象",将物品放入背包的过程称为”方法“。

面向过程的实现方法

面向过程中没有“方法”概念,只能通过结构体和函数,由使用者用函数参数和调用关系来形成接近”方法“的概念。

package main

import "fmt"

type Bag struct {
items []int
} func Insert(b *Bag, itemid int) {
b.items = append(b.items, itemid)
} func main() {
bag := &Bag{}
Insert(bag, 100)
fmt.Println(bag.items)
}

Go 语言结构体方法

将背包及放入背包物品中使用go语言的结构体和方法方式编写,为 *Bag创建一个方法。

package main

import "fmt"

type Bag struct {
items []int
} func (b *Bag) Insert(itemid int) {
b.items = append(b.items, itemid)
} func main() {
bag := &Bag{}
bag.Insert(100)
fmt.Println(bag.items)
}

Insert(itemid int)的写法与函数一致,(b *Bag)表示接收器,即Insert作用的对象实例。每个方法只能有一个接收器。

接收器--方法作用的目标

func (接收器变量 接收器类型) 方法名(参数列表) (返回参数) {}

指针和非指针接收器的使用

在计算机中,小对象由于值复制时的速度较快,适合使用非针接收器。大对象因为复制性能较低,适合使用指针接收器,在接收器和参数间传递 不进行复制, 只是传指针。

指针类型接收器

指针类型接收器由一个结构体指针组成,更接近于面向对象中的thisself

由于指针的特性,调用方法时,修改接收器成员变量,在方法结束后是有效的。

package main

import "fmt"

type Property struct {
value int
} func (p *Property) SetValue(value int) {
p.value = value
} func (p *Property) Value() int {
return p.value
} func main() {
p := &Property{}
p.SetValue(1)
fmt.Println(p.Value())
}

非指针类型接收器

当方法作用于非指针接收器时,go语言会在代码运行时将接收器的值复制一份。在非指针接收器的方法中可以获取接收器的成员值,但修改后无效

package main

import "fmt"

type Point struct {
X int
Y int
} func (p Point) Add(other Point) Point {
return Point{p.X+other.X, p.Y+other.Y}
} func main() {
p1 := Point{1, 1}
p2 := Point{3, 4}
fmt.Println(p1.Add(p2))
}

示例,time时间的中的Second属性是 Duration,Duration拥有String()方法。

package main

import (
"fmt"
"time"
) func main() {
fmt.Println(time.Second.String())
} //const (
// Nanosecond Duration = 1
// Microsecond = 1000 * Nanosecond
// Millisecond = 1000 * Microsecond
// Second = 1000 * Millisecond
// Minute = 60 * Second
// Hour = 60 * Minute
//)
//
//func (d Duration) String() string {
// ...
// return string(buf[w:])

结构体内嵌

结构体允许其成员字段在声明时没有宇段名而只有类型,这种形式的字段被称为类型内嵌。

type Data struct {
int
float32
bool
} ins : = &Data{
int: 1 0,
float32 : 3 .14,
bool: true
}

结构体类型内嵌比普通类型内嵌的概念复杂 ,下面通过一个实例来理解。

package main

import "fmt"

type BasicColor struct {
R, G, B float32
} type Color struct {
Basic BasicColor
Alpha float32
} func main() {
var color Color
color.Basic.R = 1
color.Basic.G = 1
color.Basic.B = 0
color.Alpha = 1
fmt.Printf("%+v", color)
}

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

package main

import "fmt"

type BasicColor struct {
R, G, B float32
} type Color struct {
BasicColor
Alpha float32
} func main() {
var color Color
color.R = 1
color.G = 1
color.B = 0
color.Alpha = 1
fmt.Printf("%+v", color)
}

初始化结构体内嵌

package main

import "fmt"

type Wheel struct {
Size int
} type Engine struct {
Power int
Type string
} type Car struct {
Wheel
Engine
} func main() {
car := Car{
Wheel: Wheel{
Size: 10,
},
Engine: Engine{
Power: 10,
Type: "Dz",
},
} fmt.Printf("%+v", car)
}

使用匿名结构体分离json数据

package main

import (
"encoding/json"
"fmt"
) // 定义屏幕
type Screen struct {
Size float32 // 屏幕尺寸
ResX, ResY int //屏幕水平和垂直分辨率
} // 定义电池
type Battery struct {
Capacity int // 容量
} func genJsonData () []byte {
raw := &struct {
Screen
Battery
HasTouchID bool
}{
Screen: Screen{
Size: 5.5,
ResX: 1920,
ResY: 1080,
},
Battery: Battery{
Capacity: 100,
},
HasTouchID: true,
}
jsonData, err := json.Marshal(raw)
if err != nil {
return make([]byte, 0)
} else {
return jsonData
}
} func main() {
// 生成一段 JSON 数据
jsonData := genJsonData()
fmt.Println(string(jsonData))
// 只需要屏幕和指纹识别信息的结构和实例
screenAndTouch := struct {
Screen
HasTouchID bool
}{} // 反序列化到 screenAndTouch
err := json.Unmarshal(jsonData, &screenAndTouch)
if err == nil {
fmt.Printf("%+v\n", screenAndTouch)
} // 只需要电池和指纹识别信息的结构和实例
batteryAndTouch := struct {
Battery
HasTouchID bool
}{} err = json.Unmarshal(jsonData, &batteryAndTouch)
if err == nil {
fmt.Printf("%+v\n", &batteryAndTouch)
}
}

go 基础 结构体的更多相关文章

  1. C#语言基础——结构体和枚举类型

    结构体和枚举类型 一.结构体(struct) 结构类型是用户自己定义的一种类型,它是由其他类型组合而成的,可包含构造函数.常数.字段.方法.属性.索引器.运算符.事件和嵌套类型的值类型.结构在几个重要 ...

  2. C#基础——结构体

    集合:数组:同一类型,固定长度集合:不同类型,不固定长度 要使用集合,必须先引用命名空间:using System.Collections; 定义:ArrayList arr = new ArrayL ...

  3. OC基础--结构体 枚举做类成员属性

    结构体  枚举作类的成员属性: 定义一个学生类 性别 -- 枚举 生日 入学日期  毕业日期  --  结构体 代码示例: 声明文件 Student.h: #import <Foundation ...

  4. C基础--结构体

    C语言,结构体语法: 1.定义结构体类型: struct 结构体名称 { 成员类型 成员名称1; 成员类型 成员名称2; ... }; 例:struct Date { int year ; int m ...

  5. C基础--结构体成员初始化方式

    之前在linux内核代码中看到结构体成员成员初始化使用类似于.owner = THIS_MODULE, 不太见过,于是搜了个博客,分享下: 转自:http://www.cnblogs.com/Anke ...

  6. C语言基础--结构体对齐,位域,联合体

    结构体对齐 1--结构体对齐的原因与意义 许多计算机系统对基本数据类型的可允许地址做出了一些限制,要求某种类型的对象的地址必须是某个值K(通常是2,4,8)的倍数,而这个k则被称为该数据类型的对齐模数 ...

  7. 2017-3-2 C#基础 结构体

    1. 结构体:用户自定义类型定义位置:定义在Main函数的外面,类的里面 定义格式:struct 自定义名字{ public 数据类型 名字; public 数据类型 名字; ... ...} 声明实 ...

  8. 数据结构基础——结构体struct及类型别名typedef的使用

    一.结构体的创建 在C语言中,实现数据结构的一种常用方法便是使用结构体(structure)其示例代码如下: struct stu { int num; char ch; }; struct表示创建结 ...

  9. C语言基础:结构体 分类: iOS学习 c语言基础 2015-06-10 21:47 28人阅读 评论(0) 收藏

    结构体:是一种用户自定义的数据类型 结构体定义 struct 结构体名 {     成员类型1  成员变量名1;     成员类型2  成员变量名2;      -. }; typedef   原类型 ...

随机推荐

  1. Hadoop Zookeeper 分布式服务框架

    what is Zookeeper? 1,开源的分布式的,为分布式应用提供协调服务的Apache项目2,提供一个简单原语集合,以便于分布式应用可以在它之上构建更高层次的同步服务3,设计非常易于编程,它 ...

  2. 《Mathematical Analysis of Algorithms》中有关“就地排列”(In Situ Permutation)的算法分析

    问题描述 把数列\((x_1,x_2,\cdots,x_n)\)变换顺序为\((x_{p(1)},x_{p(2)},\cdots,x_{p(n)})\),其中\(p\)是\(A=\{1,2,3,\cd ...

  3. ASP.NET Core MVC通过IViewLocationExpander扩展视图搜索路径

    IViewLocationExpander API ExpandViewLocations Razor视图路径,视图引擎会搜索该路径. PopulateValues 每次调用都会填充路由 项目目录如下 ...

  4. Windows命令help的基本使用

  5. LeetCode 题解 | 70. 爬楼梯

    假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 示例 1: 输入: 2 输出: 2 解释: 有两 ...

  6. SpringCloud Alibaba01-Nacos

    全家桶介绍: https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html ...

  7. 在tap的碎片上与活动进行绑定实现点击事件(日期时间选择以及按钮跳转时间)

    主要是掌握怎样在Fragment类型的.java文件中实现对于文本框或者按钮点击事件的触发操作. 相应的出发时间都是之前的代码.主要是怎样在Fragment怎样实现相应的操作主要是对于getActiv ...

  8. 模板继承和UImodul 和 UImethods

     模板继承和UImodul 和 UImethods 模板的继承 {% extends path %} path为templates下的相对路径 {% block block_name %}conten ...

  9. GhostNet: 使用简单的线性变换生成特征图,超越MobileNetV3的轻量级网络 | CVPR 2020

    为了减少神经网络的计算消耗,论文提出Ghost模块来构建高效的网络结果.该模块将原始的卷积层分成两部分,先使用更少的卷积核来生成少量内在特征图,然后通过简单的线性变化操作来进一步高效地生成ghost特 ...

  10. 23 抽象类 abstract

    /*概念 * abstract:关键字,用于修饰方法和类 * 抽象方法:不同类的方法是相似,但是具体内容又不太一样,所以我们只能抽取他的声明,没有具体的方法体,没有具体方法体的方法就是抽象方法 * 抽 ...