指针

指针操作
  • 指针包括指针地址、指针类型和指针取值

  • &: &符号放在变量前面进行取地址操作

  • **:*放在变量前面根据地址进行取值

指针地址:
  1. func main() {
  2. var a int = 1
  3. // a的值是1--类型是int--,地址是0xc0000120c0,&是地址符号
  4. fmt.Printf("a的值是%v--类型是%T--,地址是%p \n", a, a, &a)
  5. // 指针变量:指针一种特殊的变量,存储的数据是另一个变量的地址
  6. // 值类型的数据都有对应的指针类型,例如*int、*int64、*string 等
  7. var b = &a
  8. // b的值是0xc0000120c0--类型是*int--,地址是0xc000056028
  9. // *int:int的指针类型,*代表指针
  10. // go中所有的变量都有自己的内存地址,指针变量也有自己的地址
  11. fmt.Printf("b的值是%v--类型是%T--,地址是%p \n", b, b, &b)
  12. }
指针取值:
  1. a := 1
  2. b := &a // 指针变量
  3. // // b的值是a的内存地址,通过*b打印该内存地址对应的值,也就是a的值
  4. fmt.Println(*b) // 1
  5. //通过内存地址改变值
  6. *b = 3
  7. fmt.Println(a) //3
make和new

所有的引用数据类型必须要分配内存空间才能赋值使用,指针也是引用数据类型

new:

new是一个内置函数,作用是动态地分配内存,返回该指针的地址,值是对应类型指针的零值

  1. // new 的参数就是数据类型,得到的是一个对应的零值的指针
  2. var num = new(bool)
  3. fmt.Println(num) // 0xc00009e012
  4. fmt.Printf("%T \n", num) // *bool
  5. fmt.Println(*num) // false
  6. *num = true
  7. fmt.Println(*num) // true

make:

make和new的区别:

  • make 只用于 slice、map 以及 channel 的初始化,返回的还是这三个引用类型本身

  • new 用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针

结构体

Golang 中没有“类”的概念,Golang 中的结构体和其他语言中的类有点相似。和其他面向对

象语言中的类相比,Golang 中的结构体具有更高的扩展性和灵活性。

Golang 中的基础数据类型可以表示一些事物的基本属性,但是当我们想表达一个事物的全

部或部分属性时,这时候再用单一的基本数据类型就无法满足需求了,Golang 提供了一种

自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称 struct。

也就是我们可以通过 struct 来定义自己的类型

类型别名:
  1. // 自定义类型
  2. type myInt int
  3. // 类型别名 通过赋值给类型取一个别名
  4. type myFloat = float64
  5. func main() {
  6. var a myInt = 1
  7. var b myFloat = 3.14
  8. //区别在于一个类型是自定义的类型,一个还是原类型
  9. fmt.Printf("%T \n", a) // main.myInt
  10. fmt.Printf("%T", b) // float64
  11. }
结构体定义

类型名:表示自定义结构体的名称,在同一个包内不能重复。

字段名:表示结构体字段名。结构体中的字段名必须唯一。

字段类型:表示结构体字段的具体类型。

使用 type 和 struct 关键字来定义结构体

  1. /*
  2. 结构体首字母可以大写也可以小写
  3. 大写表示这个结构体是公有的,在其他的包里面可以使用。小写表示这个结构体是私有的,只有这个包里面才能使用
  4. */
  5. // Person 类型名
  6. type Person struct {
  7. // 包含的属性 和类型
  8. name, sex string
  9. age int
  10. }
实例化结构体
  • 只有当结构体实例化时,才会真正地分配内存。也就是必须实例化后才能使用结构体的字段
  • 结构体如果定义了字段,没有赋值,则默认是类型默认值
方法一 var 关键字实例化结构体 :

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

  1. func main() {
  2. // 声明p变量,类型是Person
  3. // 实例化Person结构体
  4. var p Person
  5. // 结构体属性赋值
  6. p.name = "lq"
  7. fmt.Println(p) // {lq 0}
  8. fmt.Println(p.name) // lq
  9. fmt.Printf("%T \n", p) // main.Person
  10. // %#v可以打印结构体的全部内容
  11. fmt.Printf("%#v", p) // main.Person{name:"lq", sex:"", age:0}
  12. }
方法二 通过new实例化结构体
  1. func main() {
  2. /*
  3. 在 Golang 中支持对结构体指针直接使用.来访问结构体的成员。p.name = "李" 其 实在底层是(*p2).name = "李”
  4. */
  5. var p = new(Person)
  6. p.name = "李"
  7. fmt.Printf("%#v \n", p) // &main.Person{name:"李", sex:"", age:0} 指针地址
  8. fmt.Printf("%T \n", p) // *main.Person 结构体指针
  9. fmt.Printf("%#v \n", *p) // main.Person{name:"李", sex:"", age:0}
  10. fmt.Println(p.name) // 李
  11. }
方法三 通过&实例化结构体
  1. func main() {
  2. /*
  3. 通过&实例化结构体,类型都和通过new实例化一样,都是指针类型
  4. */
  5. var p = &Person{}
  6. p.name = "li"
  7. }
方法四 通过键值对实例化结构体
  1. func main() {
  2. var p = Person{
  3. name: "l",
  4. sex: "1",
  5. age: 10, // 必须有逗号
  6. }
  7. fmt.Printf("%#v \n", p) // main.Person{name:"l", sex:"1", age:10}
  8. fmt.Printf("%T \n", p) // main.Person
  9. }
方法五 结构体指针键值对实例化
  1. func main() {
  2. var p = &Person{
  3. name: "l",
  4. sex: "1",
  5. age: 10, // 必须有逗号
  6. }
  7. fmt.Printf("%#v \n", p) // &main.Person{name:"l", sex:"1", age:10}
  8. fmt.Printf("%T \n", p) // *main.Person
  9. }
方法六 不指定键值根据顺序赋值
  1. func main() {
  2. // &地址or 直接声明都可以
  3. // 赋值顺序要和定义的key顺序一致
  4. var p = Person{
  5. "l",
  6. "1",
  7. 10, // 必须有逗号
  8. }
  9. fmt.Printf("%#v \n", p) // main.Person{name:"l", sex:"1", age:10}
  10. fmt.Printf("%T \n", p) // main.Person
  11. }
结构体方法和接收者

在 go 语言中,没有类的概念但是可以给类型(结构体,自定义类型)定义方法

方法就是定义了接收者的函数,接收者的概念就类似于其他语言中的 this 或者 self

  • 接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名的第一个小

    写字母,例如Person 类型的接收者变量应该命名为 p

  • 接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型

  • 方法名、参数列表、返回参数:格式与函数定义相同

  • 结构体是一个值类型,改变副本时不会影响原数据

结构体方法
  1. // 结构体
  2. type Person struct {
  3. name string
  4. age int
  5. sex string
  6. height int
  7. }
  8. /*
  9. 语法: func (接收者变量 接收者类型) 结构体方法名(参数) 返回值 {}
  10. p:接收者变量
  11. Person:接收者类型
  12. PrintInfo:自定义的结构体方法名
  13. */
  14. func (p Person) PrintInfo() {
  15. // 通过接收者变量p 调用 类似于self、 this
  16. fmt.Println(p.name)
  17. }
  18. // 接收者类型也可以是 指针,多个实例化 值类型与引用类型的区别
  19. func (p *Person) setInfo(name string) {
  20. // 通过指针修改
  21. p.name = name
  22. }
  23. func main() {
  24. // 实例化 设置值
  25. var pe = Person{
  26. name: "l",
  27. age: 20,
  28. sex: "m",
  29. height: 180,
  30. }
  31. var pe1 = Person{
  32. name: "l",
  33. age: 20,
  34. sex: "m",
  35. height: 180,
  36. }
  37. // p1的指针类型修改name
  38. pe1.setInfo("q")
  39. // 每个结构体实例都是独立的,不会互相影响
  40. pe.PrintInfo() // l
  41. pe1.PrintInfo() // q
  42. }
给任意类型添加方法

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

  1. // 自定义myInt类型
  2. type myInt int
  3. // 结构体方法 类型是自定义类型
  4. func (m myInt) test() {
  5. fmt.Println("自定义类型的自定义方法")
  6. }
  7. func main() {
  8. var a myInt = 20
  9. a.test() // 自定义类型的自定义方法
  10. }
结构体匿名字段

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

匿名字段默认采用类型名作为字段名,,因此一个结构体中同种类型的匿名字段只能有一个

  1. type Test struct {
  2. string // 类型不能重复
  3. int
  4. }
  5. func main() {
  6. var test = Test{
  7. "li",
  8. 20,
  9. }
  10. fmt.Println(test) // {li 20}
  11. }
结构体嵌套:
  • 一个结构体中可以嵌套包含另一个结构体或结构体指针

  • 结构体的字段类型可以是基本数据类型、切片、map以及结构体

  • 如果结构体的字段类型是指针、slice、map,零值都是nil,还没有分配空间,如果需要使用这样的字段,需要先make,再使用

      1. /* 零值字段类型初始化赋值 */
      2. type Person struct {
      3. Name string
      4. Age int
      5. hobby []string
      6. Extent map[string]string
      7. }
      8. func main() {
      9. var person Person
      10. person.Name = "li"
      11. person.Age = 20
      12. // 初始化切片
      13. person.hobby = make([]string, 3, 6)
      14. // 切片赋值
      15. person.hobby[0] = "eat"
      16. person.hobby[1] = "eat"
      17. person.hobby[2] = "eat"
      18. // 初始化map
      19. person.Extent = make(map[string]string)
      20. // map赋值
      21. person.Extent["height"] = "180"
      22. fmt.Println(person.hobby) // [eat eat eat]
      23. }

结构体嵌套:

  1. /*
  2. 结构体嵌套
  3. */
  4. type User struct {
  5. Username string
  6. Password string
  7. Address Address // 表示User结构体中嵌套Address结构体
  8. }
  9. type Address struct {
  10. Name string
  11. Phone string
  12. City string
  13. }
  14. func main() {
  15. // 实例化user
  16. var u User
  17. u.Username = "li"
  18. u.Password = "123"
  19. // user中声明了Address,类型是Address
  20. u.Address.Name = "北京"
  21. u.Address.Phone = "1231231"
  22. u.Address.City = "北京"
  23. fmt.Printf("%#v", u) // main.User{Username:"li", Password:"123", Address:main.Address{Name:"北京", Phone:"1231231", City:"北京"}}
  24. }

匿名结构体:

  1. type User struct {
  2. Username string
  3. Password string
  4. Address // 匿名结构体
  5. }
  6. type Address struct {
  7. Name string
  8. Phone string
  9. City string
  10. }
  11. func main() {
  12. // 实例化user
  13. var u User
  14. u.Username = "li"
  15. u.Password = "123"
  16. /*
  17. 匿名嵌套可以直接通过U.Name访问 嵌套的Address中的属性
  18. 当访问结构体成员时会先在结构体中查找该字段,找不到再去匿名结构体中查找
  19. 所以如果使用该简写方式,两个结构体有相同字段,则会访问第一个
  20. 如果是嵌套了两个子结构体,这两个子结构体有相同字段,使用简写访问会报错,因为不知道访问哪个
  21. */
  22. u.Name = "北京"
  23. u.Phone = "1231231"
  24. u.Address.City = "北京"
  25. fmt.Printf("%#v", u) // main.User{Username:"li", Password:"123", Address:main.Address{Name:"北京", Phone:"1231231", City:"北京"}}
  26. }
结构体继承

结构体继承是通过嵌套来实现的,可以嵌套结构体,也可以另一个结构体的指针

  1. // Animal 父结构体
  2. type Animal struct {
  3. Name string
  4. }
  5. // Animal结构体方法
  6. func (a Animal) aFunc() {
  7. fmt.Println(a.Name)
  8. }
  9. // Dog 子结构体
  10. type Dog struct {
  11. weight int
  12. Animal Animal // 通过结构体嵌套,Dog拥有Animal的属性方法,实现继承
  13. }
  14. // Dog 结构体方法
  15. func (d Dog) dFunc() {
  16. fmt.Println(d.Animal.Name)
  17. }
  18. func main() {
  19. // 实例化结构体
  20. var d = Dog{
  21. weight: 100,
  22. // 实例化嵌套的结构体
  23. Animal: Animal{
  24. Name: "大黄",
  25. },
  26. }
  27. fmt.Printf("%#v \n", d) // main.Dog{weight:100, Animal:main.Animal{Name:"大黄"}}
  28. d.Animal.aFunc() // 大黄
  29. d.dFunc() // 大黄
  30. }
结构体和json相互转换
序列化:
  1. /* json序列化 */
  2. import (
  3. "encoding/json" // 导入包
  4. "fmt"
  5. )
  6. type Student struct {
  7. ID int
  8. Gender string
  9. Name string
  10. height int // 小写开头是私有属性,私有属性不能被json包访问
  11. }
  12. func main() {
  13. var s1 = Student{
  14. ID: 0,
  15. Gender: "m",
  16. Name: "l",
  17. height: 10,
  18. }
  19. fmt.Printf("%#v \n", s1) // main.Student{ID:0, Gender:"m", Name:"l", height:10}
  20. // 使用json.Marshal()处理结构体,两个返回值,第一个是是一个Byte数组,第二个是错误信息
  21. // 将结构体对象转换成字节数组
  22. var jonByte, _ = json.Marshal(s1)
  23. fmt.Println(jonByte) // [123 34 73 68 34 58 48 44 34 71 101 110 100 101 114 34 58 34 109 34 44 34 78 97 109 101 34 58 34 108 34 125]
  24. // 将字节数组 转换成 json字符串
  25. var jsonStr = string(jonByte)
  26. fmt.Printf("%#v \n", jsonStr) // "{\"ID\":0,\"Gender\":\"m\",\"Name\":\"l\"}" height是私有属性,无法访问
  27. }
反序列化:
  1. /* json 反序列化 */
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. type Student struct {
  7. Id int
  8. Gender string
  9. Name string
  10. }
  11. func main() {
  12. // json字符串
  13. var jsonStr string = "{\"ID\":0,\"Gender\":\"m\",\"Name\":\"l\"}"
  14. // 实例化Student
  15. var s Student
  16. // json.Unmarshal 将json字符串转换成结构体对象,第一个值是byte类型的切片,第二个值是要转换的结构体对象的地址,需要&
  17. // 如果反序列化成功,方法返回值就是nil,对应的数据直接赋值到结构体,无需变量接收
  18. err := json.Unmarshal([]byte(jsonStr), &s)
  19. // 判断是否反序列化成功
  20. if err == nil {
  21. fmt.Printf("%#v", s) // main.Student{Id:0, Gender:"m", Name:"l"}
  22. }
  23. }
嵌套结构体和 JSON 序列化反序列化
  1. import (
  2. "encoding/json"
  3. "fmt"
  4. )
  5. type Student struct {
  6. ID int
  7. Name string
  8. }
  9. type Class struct {
  10. Title string
  11. Student []Student // Student类型的的切片,一个班级里可以有多个学生
  12. }
  13. func main() {
  14. c := Class{
  15. Title: "小葵花课堂",
  16. // 初始化切片
  17. Student: make([]Student, 0),
  18. }
  19. // 向班级实例c的Student切片 添加数据
  20. s := Student{ID: 1, Name: "1"}
  21. c.Student = append(c.Student, s)
  22. // main.Class{Title:"小葵花课堂", Student:[]main.Student{main.Student{ID:1, Name:"1"}}}
  23. fmt.Printf("%#v\n", c)
  24. // 序列化
  25. jsonByte, _ := json.Marshal(c)
  26. jsonStr := string(jsonByte)
  27. // "{\"Title\":\"小葵花课堂\",\"Student\":[{\"ID\":1,\"Name\":\"1\"}]}"
  28. fmt.Printf("%#v\n", jsonStr)
  29. var cl Class
  30. // 反序列化
  31. _ = json.Unmarshal([]byte(jsonStr), &cl)
  32. fmt.Printf("%#v\n", cl) // main.Class{Title:"小葵花课堂", Student:[]main.Student{main.Student{ID:1, Name:"1"}}}
  33. }
结构体标签Tag

Tag 是结构体的元信息,可以在运行的时候通过反射的机制读取出来

Tag 在结构体字段的后方定义,由一对反引号包裹起来,具体的格式如下:

  1. key1:"value1" key2:"value2"

结构体 tag 由一个或多个键值对组成。键与值使用冒号分隔,值用双引号括起来。同一个结

构体字段可以设置多个键值对 tag,不同的键值对之间使用空格分隔。

注意事项: 为结构体编写 Tag 时,必须严格遵守键值对的规则。结构体标签的解析代码的

容错能力很差,一旦格式写错,编译和运行时都不会提示任何错误,通过反射也无法正确取

值。例如不要在 key 和 value 之间添加空格

  1. type Student struct {
  2. Id int `json:"id"` // /通过指定 tag 实现 json 序列化后大写ID 变成小写id
  3. Gender string `json:"呵呵"` // 通过指定 tag 实现 json 序列后keyGender 变成呵呵
  4. Name string
  5. }
  6. func main() {
  7. var student Student
  8. j, _ := json.Marshal(student)
  9. jsonStr := string(j)
  10. fmt.Printf("%#v", jsonStr) // "{\"id\":0,\"呵呵\":\"\",\"Name\":\"\"}"
  11. }

golang指针和结构体的更多相关文章

  1. 将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. ...

  2. c语言指针与结构体

    #include <stdio.h> #include <stdlib.h> struct mydata { int num; ]; }; void main1() { /*i ...

  3. 深入理解C指针之六:指针和结构体

    原文:深入理解C指针之六:指针和结构体 C的结构体可以用来表示数据结构的元素,比如链表的节点,指针是把这些元素连接到一起的纽带. 结构体增强了数组等集合的实用性,每个结构体可以包含多个字段.如果不用结 ...

  4. Android For JNI(五)——C语言多级指针,结构体,联合体,枚举,自定义类型

    Android For JNI(五)--C语言多级指针,结构体,联合体,枚举,自定义类型 我们的C已经渐渐的步入正轨了,基础过去之后,就是我们的NDK和JNI实战了 一.多级指针 指针的概念我们在前面 ...

  5. 【阅读笔记】《C程序员 从校园到职场》第七章 指针和结构体

    原文地址:让你提前认识软件开发(13):指针及结构体的使用 CSDN博客 https://blog.csdn.net/zhouzhaoxiong1227/article/details/2387299 ...

  6. 36深入理解C指针之---结构体的内存处理

    一.有关结构体的内存处理包括,结构体指针和结构体成员指针的内存分配.结构体成员的数据对齐.结构体的内存释放 1.定义:与自定义数据类型(结构体)有关的内存分配.大小和释放问题 2.特征: 1).用内存 ...

  7. 35深入理解C指针之---结构体基础

    一.结构体基础 1.定义:结构体大大加强了C的数据聚合能力,可以使得不同类型的数据进行结合 2.特征: 1).结构体可以使得不同类型的数据进行结合 2).结构体可以使用内置的数据类型,包括指针 3). ...

  8. C++ 利用指针和数组以及指针和结构体实现一个函数返回多个值

    C++ 利用指针和数组实现一个函数返回多个值demo1 #include <iostream> using namespace std; int* test(int,int,int); i ...

  9. C语言--- 高级指针2(结构体指针,数组作为函数参数)

    一.结构体指针 1. 什么是结构体指针?指向结构体变量的指针     结构体:     typedef  struct stu{                          char name[ ...

  10. (60) 结构体指针、结构体变量嵌套、结构体指针嵌套、函数指针、数组指针、指针数组、typedef 综合运用

    #include<stdio.h> #include<iostream> #include<malloc.h> /* author : 吴永聪 program: 结 ...

随机推荐

  1. [转帖]Linux中的用户和用户组

    https://www.jianshu.com/p/76700505cac4 1,Linux中的用户分类 超级用户:拥有对系统的最高管理权限,默认是root用户. 普通用户:只能对自己目录下的文件进行 ...

  2. Redis Cluster in K3S

    Redis Cluster in K3S 学习资料 https://www.cnblogs.com/cheyunhua/p/15619317.html https://blog.csdn.net/cq ...

  3. redis 6源码解析之 ziplist

    ziplist ziplist结构 ziplist的布局如下,所有的字符默认使用小端序保存: +--------+--------+--------+--------+-------+-------+ ...

  4. 我们开源了一个 Ant Design 的单元测试工具库

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:佳岚 欢迎大家点一个小小的 Star ant-design ...

  5. 【DS】P9062 [Ynoi2002] Adaptive Hsearch&Lsearch(区间最近点对)

    Problem Link 给定平面上 \(n\) 个点,\(Q\) 次询问编号在 \([l,r]\) 内的点的最近点对.\(n,Q\le 2.5\times 10^5\). 技巧:平面网格化 乱搞都是 ...

  6. MySQL查询聚合函数与分组查询

    连接数据库 mysql -hlocalhost -uroot -proot 聚合函数 聚合函数:作用于某一列,对数据进行计算. ps: 所有的null值是不参与聚合函数的运算的. 06 常见的聚合函数 ...

  7. 如何写出高质量的代码 data 组件 函数 注释 命名 变量的次数

    今天在将以前文件上传的地方全部 改为新的文件上传的api. 在改动的过程中,发现代码有很多不合理的地方 在改的时候,因此也是非常的痛苦的哈. 比如说在data中我有太多的flag标识.俩控制元素的显示 ...

  8. 【NSSCTF-Round#16】 Web和Crypto详细完整WP

    每天都要加油哦!    ------2024-01-18  11:16:55 [NSSRound#16 Basic]RCE但是没有完全RCE <?php error_reporting(0); ...

  9. 新建立git分支,之后将分支合并到master上

    1.打开PowerShell 进入解决方案中的文件夹中,并列出目前远程的所有分支 命令:git branch -a 2.从远程获取最新版本到本地 命令:git fetch --all 3.使本地代码与 ...

  10. TienChin 渠道管理-工程创建

    因为本文章主要围绕着项目开发进行,所以前言不做开头,直接上内容. 添加字段 我们的渠道表,我看到若依脚手架当中有一个是否删除的标志字段,所以我这里也添加一下: ALTER TABLE `tienchi ...