Golang 语法之结构体

2018-12-30 language golang

类似于 C 中的结构体,也就是用户自定义的类型,它代表若干字段的集合。

这里简单介绍其使用方法。

简介

GoLang 中无法通过类似 C 中的 Sizeof 直接获取结构体的大小,只能通过 unsafe.Sizeof() 获取变量大小。这也就意味着,如果要获取结构体大小,需要先声明一个变量,实际上,可以使用类似 unsafe.Sizeof(Package{}) 这种操作。

对于 GoLang 的结构体,在编译器编译时会采用类似 C 的字节对齐操作,不过与 C 语言不同的是,在利用 binary 操作时会自动规避掉,无需手动设置。

注意,如果一个结构体类型的名称以大写字母开头,则该结构体被导出,其它包可以访问它;同样,如果结构体中的字段名以大写字母开头,则这些字段也可以被其他包访问。

使用

如下是简单的使用。

package main

import (
	"fmt"
)

type Person struct {
	Name string
	Age  int
}

func main() {
	p := Person{
		Name: "Jack",
		Age:  30,
	}
	fmt.Printf("Got Person %#v\n", p)
}

上述会打印 Got Person main.Person{Name:"Jack", Age:30}

格式化

可以指定格式化的内容。

package main

import (
	"fmt"
)

type Person struct {
	Name string
	Age  int
}

func (p *Person) String() string {
	return fmt.Sprintf("%s-%d", p.Name, p.Age)
}

func main() {
	p := &Person{
		Name: "Jack",
		Age:  30,
	}
	fmt.Printf("Got Person %s\n", p)
}

默认输出 Got Person &{Jack %!s(int=30)} ,当添加了 String() 函数实现后会输出 Got Person Jack-30

匿名字段

定义结构体类型时可以仅指定字段类型而不指定字段名字,那么,此时的这种字段叫做匿名字段 (Anonymous Field)。

package main

import (
        "fmt"
)

type Person struct {
        string
        int
}

func main() {
        /* p := Person{string: "Jack", int: 30} */
        p := Person{"Jack", 30}
        fmt.Printf("Current Person %#v\n", p)
        fmt.Printf("And Person Name %#v\n", p.string)
}

虽然匿名字段没有名字,但是默认名字为类型名,那么上述的 Person 可以通过 Person.string 引用。当然,这只适用于不同类型的字段,否则将会报错。

嵌套 VS. 字段提阶

结构体的字段也可以是一个结构体,这种结构体称为嵌套结构体。

如果结构体中的匿名字段是结构体,这个匿名结构体中字段成为提阶字段 (Promoted Fields),可以从外部结构体直接访问匿名结构体类型中的字段,就像这些字段原本属于外部结构体一样。

package main

import (
        "fmt"
)

type Address struct {
        City, State string
}
type Person struct {
        Name string
        Age  int
        // address Address // 嵌套
        Address // 字段提阶
}

func main() {
        p := Person{
                Name: "Jack",
                Age:  30,
                Address: Address{
                        City:  "HangZhou",
                        State: "ZheJiang",
                },
        }
        fmt.Printf("Got Person %#v\n", p)

        /* Replace */
        p.Address = Address{
                City:  "NanJing",
                State: "JiangSu",
        }
        fmt.Printf("Got New Person %#v\n", p)

        fmt.Printf("And it's City %s\n", p.City)
}

上面的程序中,Person 结构体有一个匿名字段 Address,这个匿名字段也是一个结构体。此时 Address 中的字段 CityState 被称为提阶字段,因为它们就好像被直接声明在 Person 里一样。

在使用时可以直接通过 p.City 引用。