结构体的定义

结构体是将零个或者多个任意类型的命令变量组合在一起的聚合数据类型。
每个变量都叫做结构体的成员。

其实简单理解,Go语言的结构体struct和其他语言的类class有相等的地位,但是GO语言放弃了包括继承在内的大量面向对象的特性,只保留了组合这个基础的特性。
所有的Go语言类型除了指针类型外,都可以有自己的方法。

先通过一个下的例子理解struct,下面的这个例子用于定义一个student的struct,这个机构体有以下属性:Name,Age,Sex,Score,分别表示这个学生的名字,年龄,性别和成绩。

package main

import (
"fmt"
) type Student struct {
Name string
Age int
Sex string
Score int
} func testStruct(){
var stu Student
stu.Name = "小A"
stu.Age = 23
stu.Sex = "man"
stu.Score = 100
fmt.Printf("name:%s age:%d score:%d sex:%s\n",stu.Name,stu.Age,stu.Score,stu.Sex)
fmt.Printf("%+v\n",stu)
fmt.Printf("%v\n",stu)
fmt.Printf("%#v\n",stu)
} func main(){
testStruct()
}

运行结果如下:

上面的这个例子中演示了定义一个struct,并且为这个struct的属性赋值,以及获取这个struct的属性值

关于Go中的struct:

  1. 用于定义复杂的数据结构
  2. struct里面可以包含多个字段(属性),字段可以是任意类型
  3. struct类型可以定义方法(注意和函数的区别)
  4. struct类型是值类型
  5. struct类型可以嵌套
  6. Go语言没有class类型,只有struct类型

定义一个struct

struct声明:

type 标识符 struct {
field1 type
field2 type
}

例子:
type Student struct {
Name string
age int
}

struct中字段的访问,和其他语言一样使用“.”点这个符号
var stu Student
stu.Name = "tom"
stu.Age = 18

赋值的时候我们是通过stu.Name同样的我们访问的时候也是通过stu.Name

struct定义的三种形式

type Student struct {
Name string
age int
}
对于上面这个结构体,我们定义的三种方式有:

  1. var stu student
  2. var stu *Student = new(Student)
  3. var stu *Student = &Student

上面三种方法中,方法2和方法3的效果是一样的,返回的都是指向结构体的指针,访问的方式如下:
stu.Name,stu.Age
(*stu).Name,(*stu).Age而这种方法中可以换成上面的方法直接通过stu.Name访问
这里是go替我们做了转换了,当我们通过stu.Name访问访问的时候,go会先判断stu是值类型还是指针类型如果是指针类型,会替我们改成(*stu).Name

struct中所有字段的内存是连续的

Go 中的struct没有构造函数,一般通过工厂模式来解决,通过下面例子理解:

package main

import (
"fmt"
) type Student struct{
Name string
Age int
} func NewStudent(name string,age int) *Student{
return &Student {
Name:name,
Age:age,
}
} func main(){
s := NewStudent("tom",23)
fmt.Println(s.Name)
}

struct中的tag

我们可以为struct中的每个字段,写上一个tag。这个tag可以通过反射的机制获取到,最常用的场景就是json序列化和反序列化

下面先写一个正常我们序列化的例子:

package main

import (
"fmt"
"encoding/json"
) type Student struct{
Name string
Age int
} func main(){
var stu Student
stu.Name = "tom"
stu.Age = 23 data,err := json.Marshal(stu)
if err != nil{
fmt.Printf("json marshal fail fail error:%v",err)
return
}
fmt.Printf("json data:%s\n",data)
}

运行结果如下:

注意:这里有个问题是我们在定义struct中的字段的时候如:Name,Age都是首字母大写的,这样你json序列化的时候才能访问到,如果是小写的,json包则无法访问到,所以就像上述的结果一样,序列化的结果也是首字母大写的,但是我就是想要小写怎么办?这里就用到了tag,将上述的代码更改为如下,序列化的结果就是小写的了:

package main

import (
"fmt"
"encoding/json"
) type Student struct{
Name string `json:"name"`
Age int `json:"age"`
} func main(){
var stu Student
stu.Name = "tom"
stu.Age = 23 data,err := json.Marshal(stu)
if err != nil{
fmt.Printf("json marshal fail fail error:%v",err)
return
}
fmt.Printf("json data:%s\n",data)
}

这里多说一个小知识就是如果我们想要把json后的数据反序列化到struct,其实方法也很简单,只需要在上述的代码后面添加如下:

var stu2 Student
err = json.Unmarshal(data,&stu2)
if err != nil{
fmt.Printf("json unmarshal fail fail error:%v",err)
return
}
fmt.Printf("%+v\n",stu2)

结构体的比较

如果结构体的全部成员都是可以比较的,那么结构体也是可以比较的,那样的话,两个结构体将可以使用==或!=运算符进行比较。相等比较运算符将比较两个机构体的每个成员
如下面例子:

package main

import (
"fmt"
) type Point struct{
x int
y int
} func main(){
p1 := Point{1,2}
p2 :=Point{2,3}
p3 := Point{1,2}
fmt.Println(p1==p2) //false
fmt.Println(p1==p3) //true }

匿名字段

结构体中字段可以没有名字
下面是一个简单的例子:

package main

import (
"fmt"
) type Student struct{
Name string
Age int
int
} func main(){
var s Student
s.Name = "tom"
s.Age = 23
s.int = 100
fmt.Printf("%+v\n",s)
}

可能上面的这里例子看了之后感觉貌似也没啥用,其实,匿名字段的用处可能更多就是另外一个功能(其他语言叫继承),例子如下:

package main

import (
"fmt"
) type People struct{
Name string
Age int
} type Student struct{
People
Score int
} func main(){
var s Student
/*
s.People.Name = "tome"
s.People.Age = 23
*/
//上面注释的用法可以简写为下面的方法
s.Name = "tom"
s.Age = 23 s.Score = 100
fmt.Printf("%+v\n",s)
}

注意:关于字段冲突的问题,我们在People中定义了一个Name字段,在Student中再次定义Name,这个时候,我们通过s.Name获取的就是Student定义的Name字段

方法

首先强调一下:go中任何自定义类型都可以有方法,不仅仅是struct
注意除了:指针和interface

通过下面简单例子理解:

package main

import (
"fmt"
) //这里是我们普通定义的一个函数add
func add(a,b int) int {
return a+b
} type Int int //这里是对Int这个自定义类型定义了一个方法add
func (i Int) add(a,b int) int{
return a+b
}
//如果想要把计算的结果赋值给i
func(j *Int) add2(a,b int){
*j = Int(a+b)
return
} func main(){
c := add(100,200)
fmt.Println(c)
var b Int
res := b.add(10,100)
fmt.Println(res) var sum Int
sum.add2(20,20)
fmt.Println(sum) }

方法的定义:

func(receiver type)methodName(参数列表)(返回值列表){

}

下面是给一个结构体struct定义一个方法

package main

import (
"fmt"
) type Student struct{
Name string
Age int
} func (stu *Student)Set(name string,age int){
stu.Name = name
stu.Age = age
} func main(){
var s Student
s.Set("tome",23)
fmt.Println(s)
}

注意:方法的访问控制也是通过大小写控制的

在上面这个例子中需要注意一个地方func (stu *Student)Set(name string,age int)这里使用的是(stu *Student)而不是(stu Student)这里其实是基于指针对象的方法

基于指针对象的方法

当调用一个函数时,会对其每个参数值进行拷贝,如果一个函数需要更新一个变量,或者函数的其中一个参数是在太大,我们希望能够避免进行这种默认的拷贝,这种情况下我们就需要用到指针了,所以在上一个代码例子中那样我们需要func (stu *Student)Set(name string,age int)来声明一个方法

这里有一个代码例子:

package main

import (
"fmt"
) type Point struct{
X float64
Y float64
} func (p *Point) ScaleBy(factor float64){
p.X *= factor
p.Y *= factor
} func main(){
//两种方法
//方法1
r := &Point{1,2}
r.ScaleBy(2)
fmt.Println(*r) //方法2
p := Point{1,2}
pptr := &p
pptr.ScaleBy(2)
fmt.Println(p) //方法3
p2 := Point{1,2}
(&p2).ScaleBy(2)
fmt.Println(p2) //相对来说方法2和方法3有点笨拙
//方法4,go语言这里会自己判断p是一个Point类型的变量,
//并且其方法需要一个Point指针作为指针接收器,直接可以用下面简单的方法
p3 := Point{1,2}
p3.ScaleBy(2)
fmt.Println(p3) }

上面例子中最后一种方法,编译器会隐式的帮我们用&p的方法去调用ScaleBy这个方法
当然这种简写方法只适用于变量,包括struct里面的字段,如:p.X

Go基础之--结构体和方法的更多相关文章

  1. Go语言基础之结构体

    Go语言基础之结构体 Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念.Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性. 类型别名和自定义类型 自定义类型 在G ...

  2. 六、golang中的结构体和方法、接口

    结构体: 1.用来自定义复杂数据结构 2.struct里面可以包含多个字段(属性) 3.struct类型可以定义方法,注意和函数的区分 4.strucr类型是值类型 5.struct类型可以嵌套 6. ...

  3. GO学习-(13) Go语言基础之结构体

    Go语言基础之结构体 Go语言中没有"类"的概念,也不支持"类"的继承等面向对象的概念.Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性. ...

  4. Swift超详细的基础语法-结构体,结构体构造器,定义成员方法, 值类型, 扩充函数

    知识点 基本概念 结构体的基本使用 结构体构造器(构造函数/构造方法) 结构体扩充函数(方法), 又称成员方法 结构体是值类型 1. 基本概念 1.1 概念介绍 结构体(struct)是由一系列具有相 ...

  5. 【Go】语法基础之结构体

    结构体的定义很简单: type Vertex struct { X, Y float64 } 可以理解为多个变量的集合. 结构体的使用: 1.直接使用: v := Vertex{1, 2} 或 var ...

  6. Go part 5 结构体,方法与接收器

    结构体 结构体定义 结构体的定义只是一种内存布局的描述(相当于是一个模板),只有当结构体实例化时,才会真正分配内存空间 结构体是一种复合的基本类型,通过关键字 type 定义为 自定义 类型后,使结构 ...

  7. go结构体的方法和普通函数

    package main import ( "fmt" "math" ) type vertex struct { X, Y float64 } //值接收者是 ...

  8. Go语言基础之结构体(面向对象编程上)

    1 自定义类型和类型别名 1.1 自定义类型 Go语言中可以基于一些基本的数据类型,使用type关键字定义自定义类型的数据 . 自定义类型定义了一个全新的类型,该新类型具有基本数据类型的特性.自定义类 ...

  9. go 结构体与方法

    go 结构体与方法   go 结构体相当于 python 中类的概念,结构体用来定义复杂的数据结构,存储很多相同的字段属性 结构体的定义 1.结构体的定义以及简单实用 package main imp ...

随机推荐

  1. 【NOIP2014提高组】飞扬的小鸟

    https://www.luogu.org/problem/show?pid=1941 从某一点开始飞直到飞出地图最少点击屏幕的次数,显然只和该点的坐标唯一相关,没有后效性,考虑用DP解.令f(i,j ...

  2. mongoDB之集合操作

    mongoDB之集合操作 mongoDB中的集合相当于mysql中的表. mongoDB中集合的创建: 第一种方式:不限制集合大小   db.createCollection("集合名称&q ...

  3. spring的aop详解

    一.aop术语 1.连接点joinpoint: 程序执行的某个特定位置:如类开始初始化之前.类初始化之后.类某个方法调用前.调用后等.Spring仅支持方法的连接点,即仅能在方法调用前.方法调用后以及 ...

  4. [Contiki系列论文之1]Contiki——为微传感器网络而生的轻量级的、灵活的操作系统

    说明:本系列文章翻译自Contiki之父Adam Dunkels经典论文,版权归原作者全部. Contiki是由Adam Dunkels及其团队开发的系统,研读其论文是对深入理解Contiki系统的最 ...

  5. 蓝牙核心技术概述(五):蓝牙协议规范(irOBEX、BNEP、AVDTP、AVCTP)

    关键词:蓝牙核心技术协议  irDA BNEP  AVDTP AVCTP 作者:xubin341719(欢迎转载,请注明作者,请尊重版权,谢谢! )欢迎指正错误,共同学习.共同进步!! 下载链接:Bl ...

  6. 根据实践经验,讲述些学习Java web能少走的弯路,内容摘自java web轻量级开发面试教程

    在和不少比较上进的初级程序员打交道的过程中,我们总结出了一些能帮到合格程序员尽快进阶的经验,从总体上来讲,多学.多实践不吃亏.本文来是从 java web轻量级开发面试教程从摘录的. 1  哪些知识点 ...

  7. ASP.NET Core 使用 Redis 客户端

    Mac OS 安装 Redis(用于连 Redis 服务器,方便查看数据):https://redis.io/topics/quickstart wget http://download.redis. ...

  8. mysql默认安装目录说明

    MySQL安装完成后不象SQL Server默认安装在一个目录,它的数据库文件.配置文件和命令文件分别在不同的目录,了解这些目录非常重要,尤其对于Linux的初学者,因为 Linux本身的目录结构就比 ...

  9. 十三、 Spring Boot 启动加载数据 CommandLineRunner

    实际应用中,我们会有在项目服务启动的时候就去加载一些数据或做一些事情这样的需求. 为了解决这样的问题,spring Boot 为我们提供了一个方法,通过实现接口 CommandLineRunner 来 ...

  10. 《跟我学IDEA》三、实用配置(行号、提示、代码等)

    上一篇博文我们介绍了idea如何配置一个maven,git,tomcat等,这一篇我们来进行一些常用设置,这些也正是idea可爱之处,大大提高了开发的效率. 第一节:idea常用配置显示行数.显示方法 ...