经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
GO基础之结构体
来源:cnblogs  作者:小禾点点  时间:2019/11/7 20:43:37  对本文有异议

  1. 1 、什么是结构体
    GO语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。

2、什么是实例化?

  • Go结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正分配内存。因此必须在定义结构体并实例化后才能使用结构体实例化就是根据结构体定义的格式创建一份与格式一致的內存区域。
  • 结构体实例之间的内存是完全独立的。
  1. package main
  2. import "fmt"
  3. func main() {
  4. //实例化方式一
  5. var stu1 Student
  6. fmt.Printf("stu1=%T,%v,%q \n", stu1, stu1, stu1)
  7. stu1.name = "zs"
  8. stu1.age = 12
  9. stu1.sex = 1
  10. fmt.Printf("stu1=%T,%v,%q \n", stu1, stu1, stu1)
  11. //实例化方式二
  12. stu2 := Student{}
  13. stu2.name = "David"
  14. stu2.age = 33
  15. stu2.sex = 1
  16. fmt.Printf("stu2=%T,%v,%q \n", stu2, stu2, stu2)
  17. //实例化方式三
  18. stu3 := Student{
  19. name: "Josh",
  20. age: 28,
  21. sex: 1,
  22. }
  23. fmt.Printf("stu3=%T,%v,%q \n", stu3, stu3, stu3)
  24. //实例化四
  25. stu4 := Student{"Ruby", 30, 0}
  26. fmt.Printf("stu3=%T,%v,%q \n", stu4, stu4, stu4)
  27. //实例化五
  28. //使用内置函数new()对结构体进行实例化,结构体实例化后形成指针类型的结构体
  29. //·new内置函数会分配内存。第一个参数是类型,而不是值,返回的值是指向该类型新分配的零值的指针。该函数用于创建某个类型的指针。
  30. stu5 := new(Student)
  31. (*stu5).name = "Running"
  32. (*stu5).age = 31
  33. stu5.sex = 0 //语法糖的方式
  34. fmt.Printf("stu3=%T,%v,%q \n", stu5, stu5, stu5) //stu3=*main.Student,&{Running 31 0},&{"Running" '\x1f' '\x00'}
  35. }
  36. //结构体的定义
  37. type Student struct {
  38. name string
  39. age int
  40. sex int8
  41. }
View Code

语法糖的概念( Syntactic sugar)

  • 语法糖,也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达( PeterJ.Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。
  • 通常来说使用语法糖能够增加程序的可读性,从而减少程序代码岀错的机会
  • 结构体和数组中都含有语法糖。
  1. package main
  2. import "fmt"
  3. func main() {
  4. arr := [4]int{1, 2, 3, 4}
  5. arr2 := &arr
  6. fmt.Println((*arr2)[3])
  7. //数组中的语法糖
  8. fmt.Println(arr2[3])
  9. //切片
  10. arr3 := []int{10, 20, 30, 40}
  11. arr4 := &arr3
  12. fmt.Println((*arr4)[3])
  13. //切片中没有语法糖
  14. //fmt.Println(arr4[3])
  15. }
View Code

 

3、结构体是值类型传递

二、深拷贝与浅拷贝

struct 默认是深拷贝

  1. package main
  2. import "fmt"
  3. func main() {
  4. stu1 := Student{"zs", 18, 0}
  5. fmt.Printf("stu1:=%T,%p,%v \n", stu1, &stu1, stu1)
  6. //stu1:=main.Student,0xc0000044a0,{zs 18 0}
  7. stu2 := stu1
  8. stu2.name = "ls"
  9. fmt.Printf("stu2:=%T,%p,%v \n", stu2, &stu2, stu2)
  10. //stu2:=main.Student,0xc000004520,{ls 18 0}
  11. fmt.Printf("stu1:=%T,%p,%v \n", stu1, &stu1, stu1)
  12. //stu1:=main.Student,0xc0000044a0,{zs 18 0}
  13. //修改stu2对stu1没有任何影响
  14. }
View Code

 

实现浅拷贝

1、直接赋值指针地址

  1. package main
  2. import "fmt"
  3. func main() {
  4. stu1 := Student{"zs", 18, 0}
  5. fmt.Printf("stu1:=%T,%p,%v \n", stu1, &stu1, stu1)
  6. //stu1:=main.Student,0xc00005a440,{zs 18 0}
  7. stu2 := &stu1
  8. stu2.name = "ls"
  9. fmt.Printf("stu2:=%T,%p,%v \n", stu2, stu2, stu2)
  10. //stu2:=*main.Student,0xc00005a440,&{ls 18 0}
  11. fmt.Printf("stu1:=%T,%p,%v \n", stu1, &stu1, stu1)
  12. //stu1:=main.Student,0xc00005a440,{ls 18 0}
  13. //修改stu2对stu1有影响
  14. }
View Code

 2、实现结构体浅拷贝:通过new()函数来实例化对象

  1. package main
  2. import "fmt"
  3. func main() {
  4. //3、实现结构体浅拷贝:通过new()函数来实例化对象
  5. d4 := new(Dog)
  6. d4.name = "多多"
  7. d4.color = "棕色"
  8. d4.age = 1
  9. d4.kind = "巴哥犬"
  10. d5 := d4
  11. fmt.Printf("d4: %T , %v , %p \n", d4, d4, d4)
  12. //d4: *main.Dog , &{多多 棕色 1 巴哥犬} , 0xc000040080
  13. fmt.Printf("d5: %T , %v , %p \n", d5, d5, d5)
  14. fmt.Println("--------------------------------------")
  15. d5.color = "金色"
  16. d5.kind = "金毛"
  17. fmt.Println("d5修改后:", d5)
  18. //d5修改后: &{多多 金色 1 金毛}
  19. fmt.Println("d4:", d4)
  20. //d4: &{多多 金色 1 金毛}
  21. }
  22. type Dog struct {
  23. name string
  24. color string
  25. age int8
  26. kind string
  27. }
View Code

 三、struct做函数参数

结构体对象或指针作为函数的参数及函数返回值

  • 结构体对象作为函数参数与结构体指针作为函数参数的不同
  • 结构体对象作为函数返回值与结构体指针作为函数返回值的不同

 

 

四、匿名结构体和匿名字段

匿名结构体

  • •没有名字的结构体。无需通过type关键字定义就可以直接使用。
  • •在创建匿名结构体时,同时要创建对象。
  • •匿名结构体由结构体定义和键值对初始化两部分组成
  1. //匿名结构体
  2. addr := struct {
  3. province, city string
  4. }{"陕西省", "西安市"}
  5. fmt.Println(addr)

结构体的匿名字段
结构体中的字段没有名字,只包含一个没有字段名的类型。这些字段被称为匿名字段。

  • •如果字段没有名字,那么默认使用类型作为字段名。
  • •注意:同一个类型只能写一个。
  • •结构体嵌套中采用匿名结构体字段可以模拟继承关系。
  1. package main
  2. import "fmt"
  3. type User struct {
  4. string
  5. byte
  6. int8
  7. float64
  8. }
  9. func main() {
  10. // 实例化结构体
  11. user:= User{"Steven" , 'm' , 35 , 177.5}
  12. fmt.Println(user)
  13. //如果想依次输出姓名、年龄、身高、性别
  14. fmt.Printf("姓名:%s \n" , user.string)
  15. fmt.Printf("身高:%.2f \n" , user.float64)
  16. fmt.Printf("性别:%c \n" , user.byte)
  17. fmt.Printf("年龄:%d \n" , user.int8)
  18. }
View Code

五、结构体的聚合

•将一个结构体作为另一个结构体的属性(字段),这种结构就是结构体嵌套。
•结构体嵌套可以模拟面向对象中的两种关系:

  • 〇聚合关系:一个类作为另_个类的属性
  • 〇继承关系:一个类作为另一个类的子类。子类和父类。
  1. package main
  2. import "fmt"
  3. type Address struct {
  4. province, city string
  5. }
  6. type Person struct {
  7. name string
  8. age int
  9. address *Address
  10. }
  11. func main() {
  12. //模拟结构体对象之间的聚合关系
  13. p := Person{}
  14. p.name = "Steven"
  15. p.age = 35
  16.  
  17. //赋值方式1:
  18. addr := Address{}
  19. addr.province = "北京市"
  20. addr.city = "海淀区"
  21. p.address = &addr
  22. fmt.Println(p)
  23. fmt.Println("姓名:", p.name)
  24. fmt.Println("年龄:", p.age)
  25. fmt.Println("省:", p.address.province)
  26. fmt.Println("市:", p.address.city)
  27. fmt.Println("-----------------------")
  28. //修改Person对象的数据,是否会影响Address对象的数据?
  29. p.address.city = "昌平区"
  30. fmt.Println("姓名:", p.name)
  31. fmt.Println("年龄:", p.age)
  32. fmt.Println("省:", p.address.province)
  33. fmt.Println("市:", p.address.city)
  34. fmt.Println("addr市:", addr.city) //?是否会受到影响?
  35. fmt.Println("-----------------------")
  36. //修改Address对象的数据,是否会影响Person对象的数据?
  37. addr.city = "大兴区"
  38. fmt.Println("姓名:", p.name)
  39. fmt.Println("年龄:", p.age)
  40. fmt.Println("省:", p.address.province)
  41. fmt.Println("市:", p.address.city)
  42. fmt.Println("addr市:", addr.city) //?是否会受到影响?
  43. fmt.Println("-----------------------")
  44. //赋值方式2
  45. p.address = &Address{
  46. province: "陕西省",
  47. city: "西安市",
  48. }
  49. fmt.Println(p)
  50. fmt.Println("姓名:", p.name)
  51. fmt.Println("年龄:", p.age)
  52. fmt.Println("省:", p.address.province)
  53. fmt.Println("市:", p.address.city)
  54. fmt.Println("-----------------------")
  55. }
View Code

六、结构体嵌套模拟继承关系

•继承是传统面向对象编程中三大特征之一。用于描述两个类之间的关系。一个类(子类、派生类)继承于另一个类(父类、超类)。
•子类可以有自己的属性和方法,也可以重写父类已有的方法。
•子类可以直接访问父类所有的属性和方法。
•提升字段:
  〇在结构体中属于匿名结构体的字段称为提升字段,因为它们可以被访问,就好像它们属于拥有匿名结构字段的结构一样。
  〇换句话说,父类中的字段就是提升字段。
•继承的意义:避免重复代码、扩展类的功能
•采用匿名字段的形式就是模拟继承关系。而模拟聚合关系时一定要采用有名字的结构体作为字段

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type Person struct {
  6. name string
  7. age int
  8. sex string
  9. }
  10. type Student struct {
  11. Person
  12. schoolName string
  13. }
  14. func main() {
  15. //1、实例化并初始化Person
  16. p1 := Person{"Steven", 35, ""}
  17. fmt.Println(p1)
  18. fmt.Println("-------------------")
  19. //2、实例化并初始化Student
  20. // 写法1:
  21. s1 := Student{p1, "北航软件学院"}
  22. printInfo(s1)
  23. //写法2:
  24. s2 := Student{Person{"Josh", 30, ""}, "北外高翻学院"}
  25. printInfo(s2)
  26. //写法3:
  27. s3 := Student{Person: Person{
  28. name: "Penn",
  29. age: 19,
  30. sex: "",
  31. },
  32. schoolName: "北大元培学院",
  33. }
  34. printInfo(s3)
  35. // 写法4:
  36. s4 := Student{}
  37. s4.name = "Daniel"
  38. s4.sex = ""
  39. s4.age = 12
  40. s4.schoolName = "北京十一龙樾"
  41. printInfo(s4)
  42. }
  43. func printInfo(s1 Student) {
  44. fmt.Println(s1)
  45. fmt.Printf("%+v \n", s1)
  46. fmt.Printf("姓名:%s, 年龄:%d , 性别:%s ,学校:%s \n", s1.name, s1.age, s1.sex, s1.schoolName)
  47. fmt.Println("-------------------")
  48. }
View Code

 

七、结构体中的方法

 

• Go语言同时有函数和方法,方法的本质是函数,但是方法和函数又具有不同点。
1、 含义不同
•函数function是一段具有独立功能的代码,可以被反复多次调用,从而实现代码复用。而方法method是一个类的行为功能,只有该类的对象才能调用。
2、 方法有接受者,而函数无接受者
• Go语言的方法methods—种作用于特定类型变量的函数。这种特定类型变量叫做Receiver (接受者、接收者、接收器)。
•接受者的概念类似于传统面向对象语言中的this或self关键字。
• Go语言的接受者强调了方法具有作用对象,而函数没有作用对象。
•—个方法就是一个包含了接受者的函数。
• Go语言中,接受者的类型可以是任何类型,不仅仅是结构体,也可以是struct类型外的其他任何类型。
3、 函数不可以重名,而方法可以重名
•只要接受者不同,则方法名可以一样。

  1. package main
  2. import "fmt"
  3. import "base"
  4. type Employee struct {
  5. name , currency string
  6. salary float64
  7. }
  8. func main() {
  9. emp1 := Employee{"Daniel" , "$" , 2000}
  10. emp1.printSalary()//员工姓名:Daniel ,薪资:$2000.00
  11. emp1.updateSalary(1000)
  12. emp1.printSalary()//员工姓名:Daniel ,薪资:$1000.00
  13. }
  14. //printSalary方法
  15. func (e Employee) printSalary() {
  16. fmt.Printf("员工姓名:%s ,薪资:%s%.2f \n", e.name , e.currency , e.salary)
  17. }
  18. func (e *Employee) updateSalary(num float64) {
  19. e.salary=num
  20. }
View Code

方法的继承与重写

  1. package main
  2. import "fmt"
  3. import "base"
  4. type Human struct {
  5. name, phone string
  6. age int
  7. }
  8. type Student struct {
  9. Human
  10. school string
  11. }
  12. type Employee struct {
  13. Human
  14. company string
  15. }
  16. func main() {
  17. s1 := Student{Human{"Daniel", "15012345678", 13}, "十一龙樾"}
  18. e1 := Employee{Human{"Steven", "17812345678", 35}, "1000phone"}
  19. s1.printName()
  20. e1.printName()
  21. s1.SayHi()
  22. e1.SayHi()
  23. }
  24. //======================方法的继承=============================
  25. func (h *Human) printName() {
  26. fmt.Println("大家好!我是%s ", h.name)
  27. }
  28. //=====================方法的重写=============================
  29. func (h *Human) SayHi() {
  30. fmt.Printf("大家好!我是%s , 我%d岁 , 联系方式:%s \n", h.name, h.age, h.phone)
  31. }
  32. func (s *Student) SayHi() {
  33. fmt.Printf("大家好!我是%s , 我%d岁 , 我在%s上学,联系方式:%s \n", s.name, s.age, s.school, s.phone)
  34. }
  35. func (e *Employee) SayHi() {
  36. fmt.Printf("大家好!我是%s , 我%d岁 , 我在%s工作,联系方式:%s \n", e.name, e.age, e.company, e.phone)
  37. }
View Code

 

原文链接:http://www.cnblogs.com/jalja/p/11795509.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号