定义

  1. type Person struct {
  2. Name string
  3. Age uint8
  4. }
  5. func main() {
  6. 方式一
  7. var p1 Person
  8. p1.Name="jack"
  9. p1.Age=19
  10. fmt.Println(p1)//{jack 19}
  11. 方式二
  12. //var p2 Person =Person{"tom",20}与下面等价
  13. var p2 Person =Person{}
  14. p2.Name="tom"
  15. p2.Age=20
  16. fmt.Println(p2)//{tom 20}
  17. 方式三
  18. var p3 *Person = new(Person) //注意通过new方式创建的实例,类型是一个指针
  19. (*p3).Name="mary"//标准方式,为什么不能*p3.Name,因为.的优先级比*高
  20. p3.Age=21//简化方式
  21. fmt.Println(*p3)//{mary 21}
  22. 方式四
  23. //var p4 *Person = &Person{"Allen",22}与下面等价
  24. var p4 *Person = &Person{}
  25. (*p4).Name="Allen"//标准方式
  26. p4.Age=22//简化方式
  27. fmt.Println(*p4)//{Allen 22}
  28. 方式五
  29. var p4 *Person = &Person{Name:"Allen"} //指定名称初始化,不需要将全部参数赋值
  30. }

细节

实例里的属性的地址是连续分布的

  1. type Human struct {
  2. Name int64
  3. Age int64
  4. Sex int64
  5. }
  6. func main() {
  7. h1 :=Human{}
  8. h1.Name=11
  9. h1.Age=11
  10. h1.Sex=11
  11. fmt.Printf("h1%p\n",&h1)
  12. fmt.Printf("h1.Name%p\th1.Age:%p\th1.Sex:%p",&h1.Name,&h1.Age,&h1.Sex)
  13. //h1.Name0xc000010380 h1.Age:0xc000010388 h1.Sex:0xc000010390
  14. //h1实例里的属性的地址是连续分布的
  15. //并且同数组,切片,map等一样,本身的地址与第一个元素的地址相同
  16. }

_

tag标签

  1. type Human1 struct {
  2. Name string
  3. Age int64
  4. Sex string
  5. }
  6. type Human2 struct {
  7. Name string `json:"name"`
  8. Age int64 `json:"age"`
  9. Sex string `json:"sex"`
  10. }
  11. func main() {
  12. h1 :=Human1{"tom",10,"男"}
  13. h2 :=Human2{"mary",20,"女"}
  14. h1str,_ := json.Marshal(h1)
  15. h2str,_ := json.Marshal(h2)
  16. fmt.Println(string(h1str))//{"Name":"tom","Age":10,"Sex":"男"}
  17. fmt.Println(string(h2str))//{"name":"mary","age":20,"sex":"女"}
  18. }

结构体支持匿名字段与基本类型的匿名字段

  1. type A struct {
  2. int
  3. n int
  4. }
  5. func main() {
  6. a :=A{1,2}
  7. fmt.Println(a.int,a.n)
  8. }

面对对象的思想

工厂模式

utlis包

  1. type student struct {
  2. Name string
  3. age int8
  4. }
  5. //由于student的首字母是小写的,因此在别的pck中是不能使用的
  6. func GetStudent(name string,age int8) *student{
  7. return &student{
  8. Name:name,
  9. age:age,
  10. }
  11. }
  12. //由于student中age字段是首字母是小写的,因此该字段在别的包是访问不到的
  13. func (s *student) GetAge() int8{
  14. return s.age
  15. }

main包

  1. func main() {
  2. s :=utlis.GetStudent("张三",18)
  3. fmt.Println("姓名=",s.Name,"年龄=",s.GetAge())
  4. }

继承

  1. type Animal struct {
  2. Name string
  3. Age int8
  4. }
  5. func (A *Animal) Eat(){
  6. fmt.Println(A.Name,"要吃东西")
  7. }
  8. func (A *Animal) Drink(){
  9. fmt.Println("喝水")
  10. }
  11. type Dog struct {
  12. Animal//实现继承
  13. Name string //重写属性
  14. }
  15. func (D *Dog) Eat(){ //重写方法
  16. fmt.Println(D.Name,"吃骨头")
  17. }
  18. func main() {
  19. //var d Dog=Dog{Animal{"旺财一号",3},"旺财二号"}//可以这样定义
  20. var d Dog
  21. //如果d.Animal.Name="旺财",Animal中Eat()方法中A.Name才拿到值
  22. //但是由于Dog重写了Name属性,设置d.Animal.Name="旺财",Dog中的Eat()方法中D.Name拿不到值
  23. d.Name="旺财"
  24. d.Age = 8 //由于dog是继承于animal的,d.Animal.Age = 8相关等价
  25. d.Eat()//狗吃骨头
  26. d.Animal.Eat()//''要吃东西,
  27. }

注意事项

  • 父类的私有属性与方法可以被子类继承
  • 有名结构体在指定属性与方法时要带上名字

    1. type Animal struct {
    2. Name string
    3. Age int8
    4. }
    5. type Dog struct {
    6. A Animal//有名结构体
    7. }
    8. func main() {
    9. var d Dog
    10. //d.Name = "旺财",语法不通过
    11. d.A.Name = "旺财"
    12. }
  • 结构体嵌套多个匿名结构体,且结构体有相同的属性与方法(同时结构体本身没有定义相同的属性与方法),那么在访问时,需要指定匿名结构体的名字

    1. type A struct {
    2. Name string
    3. Age int8
    4. }
    5. type B struct {
    6. Name string
    7. Age int8
    8. Sex string
    9. }
    10. type C struct {
    11. A
    12. B
    13. }
    14. func main() {
    15. var c C
    16. //c.Name="旺财" //语法不通过,A与B中都有Name属性
    17. c.A.Name="旺财"
    18. c.Sex="男" //只有B中有Sex属性,所以可以这样使用
    19. }
  • 组合嵌套的其他定义方式

    1. type A struct {
    2. Name string
    3. Age int8
    4. }
    5. type B struct {
    6. Sex string
    7. }
    8. type C struct {
    9. A
    10. B
    11. }
    12. type D struct {
    13. *A
    14. *B
    15. }
    16. func main() {
    17. 方式一:
    18. var c C=C{A{"旺财一号",3},B{"男"}}
    19. 方式二:
    20. var c2 C=C{
    21. A{
    22. Name:"旺财二号",
    23. Age:3,
    24. },
    25. B{
    26. Sex:"男",
    27. },
    28. }
    29. 指针型方式一:
    30. d :=D{&A{"旺财三号",3},&B{"男"}}
    31. 指针型方式二:类似普通型方式二
    32. fmt.Println(*d.A,*d.B)//注意这里不能用(*d).A,d不是指针,d.A才是指针
    33. }

结构体内字段分布具有连续性

1.结构体内无引用类型

  1. type Person struct {
  2. Name string
  3. Age int8
  4. Addr string
  5. }
  6. func main() {
  7. p := &Person{
  8. Name:"aaa",
  9. Age:20,
  10. Addr:"***",
  11. }
  12. fmt.Printf("p变量地址:%p\n", &p) // 0xc000098018
  13. fmt.Printf("Person地址:%p\n", p) // 0xc000074330
  14. fmt.Printf("Name地址:%p\n", &p.Name) // 0xc000074330
  15. fmt.Printf("Age地址:%p\n", &p.Age) // 0xc000074340
  16. fmt.Printf("Addr地址:%p\n", &p.Addr) // 0xc000074348
  17. }

内存分布图
image.png

2.结构体内有引用类型

还是具有连续性的特征

  1. type Person struct {
  2. Cars []string
  3. Name string
  4. Age int8
  5. Addr string
  6. }
  7. func main() {
  8. p := &Person{
  9. Cars:[]string{"audi","buick"},
  10. Name:"aaa",
  11. Age:20,
  12. Addr:"***",
  13. }
  14. fmt.Printf("p变量地址:%p\n", &p) // 0xc000098018
  15. fmt.Printf("Person地址:%p\n", p) // 0xc00001a0c0
  16. fmt.Printf("Cars地址:%p\n", &p.Cars) // 0xc00001a0c0
  17. fmt.Printf("Name地址:%p\n", &p.Name) // 0xc00001a0d8
  18. fmt.Printf("Age地址:%p\n", &p.Age) // 0xc00001a0e8
  19. fmt.Printf("Addr地址:%p\n", &p.Addr) // 0xc00001a0f0
  20. }

3.%v与%p的理解

  1. type InfoS struct {
  2. Addr string
  3. }
  4. type Person1 struct {
  5. Info *InfoS
  6. }
  7. func main() {
  8. p := &Person1{new(InfoS)}
  9. fmt.Printf("%p\n", &p) // 0xc000006028
  10. fmt.Printf("%p\n", p) // 0xc000006030
  11. fmt.Printf("%p\n", p.Info) // 0xc00003a1f0
  12. fmt.Printf("%p\n", &p.Info) // 0xc000006030
  13. fmt.Printf("%v\n", p) // &{0xc00003a1f0}
  14. // p存的是指针,用%v时,如果是指针类型,会默认对指针做一次取值操作,注意是一次
  15. }

image.png

其他

类型为func

  1. type Myfunc func(i, n int64) bool
  2. func (m Myfunc) run1(i, n int64) bool {
  3. return m(1, 2)
  4. }
  5. func (m Myfunc) run2(i, n int64) bool {
  6. return i > n
  7. }
  8. func main() {
  9. f := Myfunc(func(i, n int64) bool {
  10. return i < n
  11. })
  12. fmt.Println(f.run1(1, 2), f.run2(1, 2)) //true false
  13. }