自定义类型和类型别名

自定义类型

在Go语言中有一些基本的数据类型,如string整型浮点型布尔等数据类型, Go语言中可以使用type关键字来定义自定义类型。

自定义类型是定义了一个全新的类型。我们可以基于内置的基本类型定义,也可以通过struct定义。例如:

// MyInt 将定义为int类型
type MyInt int
func main() {
var a MyInt
fmt.Println(a) //
fmt.Printf("%T \n", a) // main.MyInt
}

通过Type关键字的定义,MyInt就是一种新的类型,它具有int的特性。

类型别名

只是给类型起了个名字,本质上是同一个类型

// Mystring 类型别名
type Mystring = string
func main() {
var s Mystring
fmt.Println(s) // 空
fmt.Printf("%T \n", s) // string
}

区别: 自定义类型是生成一个新的类型,类型别名不会产生新的类型

结构体

Go语言中的基础数据类型可以表示一些事物的基本属性,但是当我们想表达一个事物的全部或部分属性时,这时候再用单一的基本数据类型明显就无法满足需求了,Go语言提供了一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称struct。 也就是我们可以通过struct来定义自己的类型了。

Go语言中通过struct来实现面向对象。

  • 构造体是值类型
  • 是一系列属性的集合

结构体的定义

使用typestruct关键字来定义结构体,具体代码格式如下:

type 类型名 struct {
字段名 字段类型
字段名 字段类型

}
  • 类型名:标识自定义结构体的名称,在同一个包内不能重复。
  • 字段名:表示结构体字段名。结构体中的字段名必须唯一。
  • 字段类型:表示结构体字段的具体类型。

结构体实例化

只有当结构体实例化时,才会真正地分配内存。也就是必须实例化后才能使用结构体的字段。

结构体本身也是一种类型,我们可以像声明内置类型一样使用var关键字声明结构体类型。

var 结构体实例 结构体类型
  • 方式一

// 结构体
type Animal struct{
name string
colour string
age int
hobby []string
}
func main() {
// 实例化结构体方式一:
var erha = Animal{
name : "二哈",
colour : "黑色",
age : 2,
hobby : []string{"吃", "拆家"},
}
fmt.Println(erha) // {二哈 黑色 2 [吃 拆家]}
// 结构体支持点访问属性
fmt.Println(erha.name) // 二哈
fmt.Println(erha.colour) // 黑色
fmt.Println(erha.age) //
fmt.Println(erha.hobby) // [吃 拆家]
// 实例化结构体时不传入属性(字段)值, 那么字段值就是其默认类型的初始值
var jinmao = Animal{}
fmt.Println(jinmao.name) // 空
fmt.Println(jinmao.age) //
fmt.Println(jinmao.colour) // 空
fmt.Println(jinmao.hobby) // []
}

我们通过.来访问结构体的字段(成员变量)

  • 方式二

// 实例化结构体方式二
var samo = new(Animal)
fmt.Println(samo) // &{ 0 []}
(*samo).name = "萨摩"
samo.age = 2
fmt.Println(samo.name, samo.age) // 萨摩 2 var keji = &Animal{}
keji.name = "柯基"
fmt.Println(keji.name) // 柯基

结构体是值类型,我们可以获取其指针进行赋值

  • 方式三

使用值的列表初始化

初始化结构体的时候可以简写,也就是初始化的时候不写键,直接写值:

// 初始化结构体简写
var douniu = Animal{
"斗牛",
"棕色",
1,
[]string{"打呼噜", "放屁"},
}
fmt.Println(douniu.name, douniu.hobby)

使用这种格式初始化时,需要注意:

  1. 必须初始化结构体的所有字段。
  2. 初始值的填充顺序必须与字段在结构体中的声明顺序一致。
  3. 该方式不能和键值初始化方式混用。

构造函数

Go语言的结构体没有构造函数,我们可以自己实现。 例如,下方的代码就实现了一个Animal的构造函数。 因为struct是值类型,如果结构体比较复杂的话,值拷贝性能开销会比较大,所以该构造函数返回的是结构体指针类型。

func newAnimal(name, colour string, age int, hobby []string) *Animal {
return &Animal{
name : name,
colour : colour,
age : age,
hobby : hobby,
}
}
p := newAnimal("熊二", "棕色", 5, []string{"吃",})
fmt.Println(p)

方法和接收者

Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于其他语言中的this或者 self

方法的定义格式:

func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
函数体
}
  • 接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名的第一个小写字母,而不是selfthis之类的命名。例如,Person类型的接收者变量应该命名为 pConnector类型的接收者变量应该命名为c等。
  • 接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型。
  • 方法名、参数列表、返回参数:具体格式与函数定义相同
// 函数 谁都可以调用
// 方法 某个具体的类型才能调用的函数
type people struct {
name string
gender string
} // 函数
func test1() {
fmt.Println("这是一个函数")
}
// 方法 这里的p相当python类中的self
func (p people)test2() {
fmt.Printf("这是people结构体的方法 %s \n", p.name)
}
func main() {
test1() // 这是一个函数
var gtq = people{
name: "光头强",
gender: "男",
}
fmt.Println(gtq.name) // 光头强
gtq.test2() // 这是people结构体的方法 光头强
}

方法与函数的区别是,函数不属于任何类型,方法属于特定的类型。

指针接收器与值接收器

type Person struct {
name string
age int
sex int
}
  • 值接收者

func (值)changeName(name string):在内部修改值,不会影响外部的值
//修改名字的方法
func (a Person)changeName(name string) {
a.name=name
fmt.Println(a)
} func main() {
var p Person=Person{name:"熊二"}
p.changeName("熊大") // 熊大
fmt.Println(p) // 熊二 不改变原结构体对象的name属性,因为结构体是值类型,被当做参数传递时,是又拷贝了一份
}
  • 指针接受者

func (指针)changeName(name string):在内部修改值,会影响外部的值
func (a *Person)changeName(name string)  {
a.name=name
fmt.Println(a)
} func main() {
var p *Person=&Person{name:"熊二"}
p.changeName("熊大") // 熊大
fmt.Println(p) // 熊大
}
  • 什么时候应该使用指针类型接收者

  1. 需要修改接收者中的值
  2. 接收者是拷贝代价比较大的大对象
  3. 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。

给任意类型添加方法

在Go语言中,接收者的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法。 举个例子,我们基于内置的int类型使用type关键字可以定义新的自定义类型,然后为我们的自定义类型添加方法。

// 可以给任意类型添加方法
// 不能给别的包定义的类型添加方法 type Myint int func (m Myint) test3(){
fmt.Println("Myint的方法")
}
func main() {
var m Myint
m.test3() // Myint的方法
}

非本地类型不能定义方法,也就是说我们不能给别的包的类型定义方法。

结构体的匿名字段

结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段就称为匿名字段。

type Person struct {
string // 把类型当做字段的名字
int
} func main() {
p := Person{
"熊二",
5,
}
fmt.Println(p.string, p.int) // 熊二 5
}

匿名字段默认采用类型名作为字段名,结构体要求字段名称必须唯一,因此一个结构体中同种类型的匿名字段只能有一个。

嵌套结构体

一个结构体中可以嵌套包含另一个结构体或结构体指针。

// 地址结构体
type Address struct {
Province string
City string
}
// 用户结构体
type User struct {
Name string
Gender string
Address Address
} func main() {
u := User{
Name: "光头强",
Gender: "男",
Address: Address{
Province: "森林省",
City: "森林市",
},
}
fmt.Println(u.Name) // 光头强
fmt.Println(u.Address) // {森林省 森林市}
fmt.Println(u.Address.Province) // 森林省
}
  • 嵌套匿名结构体

当访问结构体成员时会先在结构体中查找该字段,找不到再去匿名结构体中查找

type Info struct {
Name string
Gender string
Address // 匿名结构体
} func main() {
var i Info
i.Name = "李雷"
i.Gender = "男"
i.Address.Province = "上海" // 通过匿名结构体.字段名访问
i.City = "上海市" // 直接访问匿名结构体的字段名
}
匿名结构体通常用作变量提升

结构体的“继承”

Go语言中使用结构体也可以实现其他编程语言中面向对象的继承。

// 利用及结构体的嵌套模拟"继承"
type animal struct {
name string
}
// 定义animal的方法
func (a *animal) move() {
fmt.Printf("%s 会动 \n", a.name)
} type Dog struct {
colour string
*animal
}
// 定义Dog的方法
func (d *Dog) run() {
fmt.Printf("%s 会跑", d.name) // 因为嵌套了animal,所以有name属性
} func main() {
var d = Dog{
colour: "黑色",
animal: &animal{name:"二哈"},
}
d.move() // 二哈 会动
d.run() // 二哈 会跑
}

结构体字段的可见性

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

结构体与JSON序列化

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。JSON键值对是用来保存JS对象的一种方式,键/值对组合中的键名写在前面并用双引号""包裹,使用冒号:分隔,然后紧接着值;多个键值之间使用英文,分隔。

import (
"encoding/json"
"fmt"
) type Student struct {
ID int
Gender string
Name string
} func main() {
s := Student{
ID: 1,
Gender: "男",
Name: "熊二",
}
// 序列化
v, err := json.Marshal(s)
if err != nil {
fmt.Println("格式错误")
}
fmt.Println(v) // []byte
fmt.Println(string(v)) // {"ID":1,"Gender":"男","Name":"熊二"}
str := string(v)
// 反序列
var stu = &Student{}
json.Unmarshal([]byte(str), stu)
fmt.Println(stu)
}

Go语言 - 结构体 | 方法的更多相关文章

  1. C语言结构体定义的几种方法

    什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate data type)的一类.结构体可以被声明为变量.指针或数组等,用以实现较复杂的数据 ...

  2. Go 语言 结构体和方法

    @ 目录 1. 结构体别名定义 2. 工厂模式 3. Tag 原信息 4. 匿名字段 5. 方法 1. 结构体别名定义 变量别名定义 package main import "fmt&quo ...

  3. Go语言结构体(struct)

    Go 语言结构体 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型. 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 结构体表示一项记录,比如保存图 ...

  4. 对嵌入式开发C语言结构体的一点总结

    今天冬至居然不上班,公司的良心啊!这回有心情写博客和日志了,好了,废话不多说.直接看下文: 鉴于嵌入式开发过程中,C语言结构体的使用当然是必不可少.话说,基础什么的比你会更牛逼的算法更重要,基础不牢, ...

  5. 在C语言结构体中添加成员函数

    我们在使用C语言的结构体时,经常都是只定义几个成员变量,而学过面向对象的人应该知道,我们定义类时,不只是定义了成员变量,还定义了成员方法,而类的结构和结构体非常的相似,所以,为什么不想想如何在C语言结 ...

  6. 将c语言的结构体定义变成对应的golang语言的结构体定义,并将golang语言结构体变量的指针传递给c语言,cast C struct to Go struct

    https://groups.google.com/forum/#!topic/golang-nuts/JkvR4dQy9t4 https://golang.org/misc/cgo/gmp/gmp. ...

  7. Linux C语言结构体-学习笔记

    Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...

  8. 读陈浩的《C语言结构体里的成员数组和指针》总结,零长度数组

    原文链接:C语言结构体里的成员数组和指针 复制例如以下: 单看这文章的标题,你可能会认为好像没什么意思.你先别下这个结论,相信这篇文章会对你理解C语言有帮助.这篇文章产生的背景是在微博上,看到@Lar ...

  9. 06. Go 语言结构体

    Go语言结构体(struct) Go 语言通过用自定义的方式形成新的类型,结构体是类型中带有成员的复合类型.Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性. Go 语言中的类 ...

随机推荐

  1. iOS 测试 WebDriverAgent 简介

    WebDriverAgent 是什么   去年的 SeleniumConf 上,Facebook 推出了一款新的iOS移动测试框架 —— WebDriverAgent,当时的推文上,写的还只支持模拟器 ...

  2. mapreduce 函数入门 一

    MapReduce 程序的业务编码分为两个大部分,一部分配置程序的运行信息,一部分 编写该 MapReduce 程序的业务逻辑,并且业务逻辑的 map 阶段和 reduce 阶段的代码分别继 承 Ma ...

  3. SQLServer ---------- 安装SQLserver数据库

    1.安装SQLserver 数据2008 的地址 https://jingyan.baidu.com/article/948f592434b407d80ef5f97d.html?qq-pf-to=pc ...

  4. [转帖]Linux firewalld 防火墙使用

    Linux firewalld 防火墙使用 2018-06-19 19:26:08 蚩尤后裔 阅读数 2101  收藏 更多 分类专栏: Linux   版权声明:本文为博主原创文章,遵循CC 4.0 ...

  5. 在RedisTemplate中使用scan代替keys指令

    keys * 这个命令千万别在生产环境乱用.特别是数据庞大的情况下.因为Keys会引发Redis锁,并且增加Redis的CPU占用.很多公司的运维都是禁止了这个命令的 当需要扫描key,匹配出自己需要 ...

  6. C# System.Reflection.Assembly动态加载资源文件

    需求:需要做甘特图的显示,并且在甘特中加载图片.图片太多,写判断代码太多.用反射吧. 核心代码: try { if (stateColour < 0) return null; System.R ...

  7. Echarts X轴多项百分比的展示

    app.title = '堆叠柱状图'; option = { tooltip : { trigger: 'axis', axisPointer : { // 坐标轴指示器,坐标轴触发有效 type ...

  8. C#实现电信短信SMGP协议程序源码

    此程序为中国电信SMGP协议程序接口,适合在中国电信申请了短信发送端口的公司使用. 短信群发已经成为现在软件系统.网络营销等必不可少的应用工具.可应用在短信验证.信息群发.游戏虚拟商品购买.事件提醒. ...

  9. Matplotlib中figure、subplot、axes、axis的区别

    参考链接:https://blog.csdn.net/JasonZhu_csdn/article/details/85860963 画图板/画布: 这是一个基础载体,类似实际的画图板,用pyplot. ...

  10. Python进阶----pymysql的安装与使用,mysql数据库的备份和恢复,mysql的事务和锁

    Python进阶----pymysql的安装与使用,mysql数据库的备份和恢复,mysql的事务和锁 一丶安装 pip install PyMySQL 二丶pymysql连接数据库 ### 语法: ...