Go编程基础——结构struct

结 构 struct
1、Go 中 的 struct 与 C 中 的 struct非常 相 似,并且 GO 没 有 class
2、使 用 type struct{} 定 义 结 构 , 名 称 遵 循 可 见 性 规 则
3、 支 持 指 向 自 身 的 指 针 类 型 成 员
4、支 持匿名 结 构, 可 用 作 成 员 或 定 义 成 员 变 量
5、匿 名 结 构 也 可 以 用 于 ma p 的 值
6、可 以 使 用 字 面值对结构进 行 初 始 化
7、允 许 直 接 通 过 指 针 来 读 写 结 构 成 员
8、相 同 类 型 的 成 员 可 进 行 直 接 拷 贝 赋 值
9、支 持 = = 与 ! = 比 较 运 算 符 , 但 不 寺 > 或 <
10、支 持 匿 名 字 段, 本 质 上 是 定 义 了 以 某 个 类 型 名 为 名 称 的 字 段
11、嵌 入 结 构 作 为 匿名 字 段 看 起 来 像 继 承 , 但 不 是 继 承
12、可 以 使 用 匿 名 字 段 指 针
首先来看看定义一个空的结构

type test struct {

}

当然他也是类型,只要是类型它就可以使用赋值

a:=test{}
fmt.Println(a)

运行结果也表示空的

{}

以下是定义一个结构以及属性、如何操作该结构的属性

type person struct {
name string
age int
}
func main() {
   a:=person{}
   a.age=15
   a.name="Bruce"
   fmt.Println(a)
}

运行结果

{Bruce 15}

也可以使用如下方法给赋值(这种方法也是Go语言中最常见的赋值手段)

a:=person{
   name:"Bruce",
   age:15}

这里值得注意的是,赋值的顺序和定义的顺序没有直接关系(后边说的匿名字段就不是这么一回事了)
struct是值类型,进行的值传递,以下程序以及运行结果可以说明

func main() {
   a:=person{
      age:15,
      name:"Bruce"}
   fmt.Println(a)
   test(a)
   fmt.Println(a)
}
func test(person person){
   person.age=100
   person.name="Hello World"
   fmt.Println(person)
}

运行结果

{Bruce 15}
{Hello World 100}
{Bruce 15}

从结果看出,确实是值传递,没有改变原始的值(因为没有进行内存地址传递)。
当然也可以使用指针来把struct的值传递改为内存地址的传递,这样就可以通过传递内存地址来修改原始的值。看如下程序

func main() {
   a:=person{
      age:15,
      name:"Bruce"}
   fmt.Println(a)
   test(&a)
   fmt.Println(a)
}
func test(person *person){
   person.age=100
   person.name="Hello World"
   fmt.Println(*person)
}

运行结果

{Bruce 15}
{Hello World 100}
{Hello World 100}

这样确实改变了原来的值,因为使用的指针进行的内存地址的拷贝
补充一下,&表示取地址的符号,星号是指针的表示,当星号用在本身是一个指针的身上,就表示去该指针指向的内存地址对应的值。就像上例中的 fmt.Println(*person)
建议在一个结构初始化的时候,可以进行取地址符号。如下:

func main() {
   a:=&person{
      age:15,
      name:"Bruce"}
      a.age=99
   fmt.Println(*a)
   test(a)
   fmt.Println(*a)
}
func test(person *person){
   person.age=100
   person.name="Hello World"
   fmt.Println(*person)
}

再一次修改a的值直接用点号(.)就可以了。这也是Go语言中比较特殊的地方,如上程序中a.age=99如果放在其他语言(如c语言)中,那得*a.age=99
匿名结构,类似于匿名函数,一个字,为了方便操作。匿名结构就是把定义属性和初始化的行为紧挨着实现,不需要结构的名字,因为它是被直接调用的

如下程序:

func main() {
   a:=struct{
      name string
      age int
   }{
      age:15,
      name:"Bruce"}
      a.age=99
   fmt.Println(a)
}

运行结果

{Bruce 99}

方便操作结构是匿名结构的意义所在。
匿名结构嵌套的普通结构中的使用很常用,有必要好好研究一下,看如下程序:
(这里要值得注意的是匿名结构的初始化方法。)

type person struct{
   age int
   name string
   contact struct{
      phone,city string
   }
}
func main() {
   a:=person{
      age:15,
      name:"Bruce"}
      a.contact.city="GuiLin"
      a.contact.phone="123456789"
   fmt.Println(a)
}

运行结果

{15 Bruce {123456789 GuiLin}}

来点Go语言中更加简约的地方,匿名字段

type person struct{
   int
   string
}
func main() {
   a:=person{
   15,
      "Bruce"}
   fmt.Println(a)
}

运行结果

{15 Bruce}

这里值得注意的是使用匿名字段时,初始化字段的顺序要和定义匿名字段的顺序一致。当然匿名字段也可以跟一般的字段结合使用。如下情况

type person struct{
   age int
   string
}
func main() {
   a:=person{
   15,
      "Bruce"}
   fmt.Println(a)
}

结构是一种类型,这也就说明同种类型可以进行相互赋值

type person struct{
   age int
   string
}
func main() {
   a:=person{
   15,
      "Bruce"}
      b:=a
   fmt.Println(b)
}

这里省略了b的类型时person,Go语言底层机制自动识别,为了说明同种类型,可以使用如下定义b

var b person
b=a

Java或者C++中都有继承,在Go语言,使用结构的嵌套(也叫做组合)来实现类似的效果,值得注意的是类似并不等同。

type human struct{
   sex int
   age int
   name string
}

type teacher struct{
   human
   level,number string
}
type student struct{
   human
   class string
   score int
}

func main() {
   teacherA:=teacher{
      level:"middle",
      number:"123456"}
      teacherA.human.age=56
      teacherA.human.sex=0
      teacherA.human.name="Bruce"
      fmt.Println(teacherA)

}

运行结果

{{0 56 Bruce} middle 123456}

组合型的结构的初始化除了上面那种还有可以有另外一种方法:

teacherA:=teacher{
   level:"middle",
   number:"123456",human:human{
      sex:0,
      age:56,
      name:"Bruce"}}

   fmt.Println(teacherA)

这里就涉及到Go语言的一个技术点,看程序human:human就知道了,因为human作为一个类型,嵌套进来那就是匿名字段,在Go语言中嵌入结构作为匿名字段被初始化时默认将结构名称human作为字段名称。

思考以下问题:
如 果 匿 名 字 段 和 外 层 结 构 有 同 名 字 段 , 应 该 如 何 进 行 操 作 ?
嵌套结构的同名字段的优先级没有外层结构同名字段的有限级别高,比如

type human struct{
   sex int
   age int
   name string
}

type teacher struct{
   name string
   human
   level,number string
}
type student struct{
   name string
   human
   class string
   score int
}

func main() {
   teacherA:=teacher{
      level:"middle",
      number:"123456"}
   teacherA.human.age=56
   teacherA.human.sex=0
   teacherA.name="Bruce"
   fmt.Println(teacherA)
}

运行结果

{Bruce {0 56 } middle 123456}

这种情况不会报出语法错误,这时候要想匿名字段(这里指类型human)中的name赋值就必须加上匿名字段的类型human,如果没有与外层结构同名的话就不需要添加human这个类型名称

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章