Golang的学习笔记(11)--Go结构体

目录

Go结构体

    Go的结构体是一种复合类型,它由一系列属性(字段)组成,每个属性(字段)都有自己的类型和值。结构体的字段可以是任何类型,甚至是结构体本身、函数、接口等
    在Go中没有类的概念,因此结构体经常被用来替代面向对象中的类的操作

Go结构体的定义

    结构体的定义格式如下:

type structName struct {
   field1 type1
   field2 type2
   ...
}
studentnameidmainstudent
type student struct{
   name string
   id int
}
func main(){
   s := student{}
   s.id = 1
   s.name = "jay"
}

    除了上面这种先创建后赋值的方式,也可以用下面的方式创建的同时为结构体的属性赋值

func main(){
  a := student{
    name: "tom",
    id: 2,
  }
}
studentpersons.p.sex
struct person{
   sex int
}
struct student{
   name string
   id int
   p person
}
func main(){
   s := student{
     name : "tongxue",
     id : 1,
     p : person{sex : 0},
   }
  s.p.sex = 1
}

匿名结构体

    Go中支持匿名结构体的操作,即不需要事先定义声明某个的结构体类型,而直接在用到的时候定义并赋值

func main(){
   c := struct {
   name string
   id int
 }{
   name : "Mike",
   id : 1
 }
}

    在结构体中使用匿名的方式定义结构体字段:

type teacher struct {
   name    string
   address struct {                
     city, stress string
   }
}        
func main(){
   d := teacher{
      name: "jake",
   }
  d.address.city = "guangzhou"
  d.address.stress = "wushanRoad"
}
addressteacherd.address.city = "guangzhou"

匿名字段

    结构体中可以包括一个或多个匿名字段,即这些字段没有显示的名字,只有字段的类型,此时默认字段的类型就是字段的名字

  • 在一个结构体内,对于每一种类型只能有一个匿名字段
  • 为匿名字段赋值的时候要注意值和匿名类型的顺序要一一对应
type killer struct{
  string
  int
}
func main(){
  k := killer{"007", 111}
  k.int = 222
  k.string = "092"
}

    同样地,匿名字段可以是一个结构体类型,即在结构体中可以嵌套匿名结构体字段,这种形式叫做内嵌结构体。内嵌结构体有点类似于面向对象语言中的继承行为,使用内嵌结构体,可以通过外部结构体直接访问到内嵌结构体中的字段(类似于继承了父类中的属性),这一点要和上面的结构体中包含结构体字段时需要一层一层嵌套访问的方式作区分

type person struct {
   sex int
}
type student struct {
  person
  name string
  id   int
}
func main(){
  e := student{
    name:  "sdk",
    id:     666,
    person: person{sex: 1},          //默认结构名为变量名
  }
  e.sex = 0      //直接访问内嵌结构体的字段
}

命名冲突

    结构体要求字段名称要唯一,如果结构体中包含同名字段怎么办?(同名字段可能来自于“继承”到内嵌结构体的字段)

  • 如果同名字段是不同层次的,(比如结构体中某字段和内嵌结构体中的字段重名了),那么直接访问该字段会访问到外层结构体的字段,如果要访问内嵌结构体的同名字段需要一层一层嵌套的方式的访问
  • 如果同名字段属于同一层次,将会引发一个错误(不使用没关系)。没有办法来解决这种问题引起的二义性,必须由程序员自己修正

结构体作函数的传入参数

    在函数中传入结构体作参数,同样是值传递,在函数内修改结构体不会对原来的结构体有影响。如果确实需要在函数体内去修改结构体,有两种方式:

  • 传递结构体指针作参数
func pointTest(s *student) {
    s.name = "nike"
    s.id = 99
    fmt.Println(s)
}
func main(){
   a := student{
        name: "tom",
        id:   2,
    }
   pointTest(&a)
}
  • 在创建结构体的时候取地址
func pointTest(s *student) {
    s.name = "nike"
    s.id = 99
    fmt.Println(s)
}
func main(){
    b := &student{
        name: "john",
        id:   12,
    }
    pointTest(b)
}
studentnameb.name = "xxx"