结构体是类型中带有成员的复合类型。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. TensorFlow系列专题(七):一文综述RNN循环神经网络

    欢迎大家关注我们的网站和系列教程:http://panchuang.net/ ,学习更多的机器学习.深度学习的知识! 目录: 前言 RNN知识结构 简单循环神经网络 RNN的基本结构 RNN的运算过程 ...

  2. js Object方法小结

    1. Object.defineProperty(obj,prop,{                 value:...,                 writable:boolean,//可写 ...

  3. Docker搭建MySQL主从复制

    Docker搭建MySQL主从复制 主从服务器上分别安装Docker 1.1 Docker 要求 CentOS 系统的内核版本高于 3.10 [root@localhost ~]# uname -r ...

  4. Selenium系列(21) - Cookie操作和源码解读

    如果你还想从头学起Selenium,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1680176.html 其次,如果你不懂前端基础知识, ...

  5. Linux 《conky配置说明书》

    名称 conky - 最初基于躯干代码的X系统监视器,但更多的kickass.它只是继续给予它.是啊. 概要 conky [ options ] 描述 Conky是最初基于torsmo的X系统监视器. ...

  6. GO gRPC教程-环境安装(一)

    前言 gRPC 是一个高性能.开源和通用的 RPC 框架,面向移动和 HTTP/2 设计,带来诸如双向流.流控.头部压缩.单 TCP 连接上的多复用请求等特.这些特性使得其在移动设备上表现更好,更省电 ...

  7. vue中的$router 和 $route的区别

    最近在学习vue的单页面应用开发,需要vue全家桶,其中用到了VueRouter,在路由的设置和跳转中遇到了两个对象$router 和 $route ,有些傻傻分不清,后来自己结合网上的博客和自己本地 ...

  8. CentOS虚拟机开机显示多内核版本

    在CentOS进行系统更新后,会保留旧版本的内核.所以,在每次启动时,会有多个内核选项,可以手动删除不用的旧版本内核.   1.查看当前系统内核版本 #uname -a   2.查看系统中存在的全部内 ...

  9. Linux系统:Centos7下搭建PostgreSQL关系型数据库

    本文源码:GitHub·点这里 || GitEE·点这里 一.PostgreSQL简介 1.数据库简介 PostgreSQL是一个功能强大的开源数据库系统,具有可靠性.稳定性.数据一致性等特点,且可以 ...

  10. selenium 鼠标滑动操作验证码

    selenium 鼠标点击操作比较简单,这里就不介绍了,主要说一下鼠标滑动(按住并滑动),经常用于解决自动化操作的滑动验证码 下面举个简单的例子,比如这种验证码: 代码: div = driver.f ...