结构体的定义

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

其实简单理解,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. Java调用PDFBox打印自定义纸张PDF

    打印对象 一份设置为A3纸张, 页面边距为(10, 10, 10, 10)mm的PDF文件. PageFormat 默认PDFPrintable无法设置页面大小. PDFPrintable print ...

  2. 使用Python提取中文字符

    #功能:国际化测试,用于提取应用设计包中的中文字符,并输出report#解压---筛选---整理路径---提取中文---输出报告 ################################### ...

  3. ssh服务、密钥登陆配置

    环境内核信息: [root@zabbix-01 ~]# uname -a Linux lodboyedu-01 2.6.32-696.el6.x86_64 #1 SMP Tue Mar 21 19:2 ...

  4. cronlog分割tomcat catalina.out日志

    Tomcat 下日志文件 catalina.out 过大,几百兆或几个G,进而造成再也无法写入更多的日志内容,至使 Tomcat 无法处理请求,所以依靠cronlog来分割: 具体步骤如下: 1.安装 ...

  5. Python爬虫(十)_正则表达式

    本篇将介绍python正则表达式,更多内容请参考:[python正则表达式] 什么是正则表达式 正则表达式,又称规则表达式,通常被用来检索.替换那些符合某个模式(规则)的文本. 正则表达式是对字符串操 ...

  6. memcached subList序列化问题

    某个业务场景需要将list超过10个元素时截取前10个然后再丢memcached缓存,因此写了这么一行代码 if(list.size()>10){ list=list.subList(0, 10 ...

  7. js----数组处理之splice(有js原始addClass方法哦)

    上次写了一个轮播的方法:http://blog.csdn.net/stronglyh/article/details/46833499 由于别人问我的时候,给了我html.于是乎我就看到了页面中引用了 ...

  8. python内置函数(四)

    python内部提供了非常多内建函数. 以下让我们从a-z開始学习python的内建函数 1.1 id(object) 返回对象的id(身份),返回的这个是一个整数(integer)是唯一的,在这个对 ...

  9. redhat5安装Oracle11g

    redhat5安装Oracle11g 测试环境redhat5.5 oracle11g VMware 虚拟机 一.linux系统安装 二.下载oracle安装包 (我们需要把oracle安装包上传到li ...

  10. 优化Webpack构建性能的几点建议

    Webpack 作为目前最流行的前端构建工具之一,在 vue/react 等 Framework 的生态圈中都占据重要地位.在开发现代 Web 应用的过程中,Webpack 和我们的开发过程和发布过程 ...