结构体

和 C 语言一样,Go 也有 struct,与数组一样属于复合类型,并非引用类型,与其他面向对象编程语言中的类一样可以定义字段(属性)和方法,但也有很不同的地方。

定义

使用 struct 关键字可以定义一个结构体,结构体中的成员称为结构体的字段或属性。

type Member struct {
    ID     int
    Name   string
    Email  string
    Gender int
}

当然你也可以这么定义。

type Member struct {
    ID          int
    Name, Email string
    Gender      int
}

结构体可以不包含任何字段,称为空结构体,struct{} 表示一个空的结构体,不过直接定义一个空的结构体并没有什么意义。 但在 channel 之间的通讯中可以用一个空结构体作为信号量。

ch := make(chan struct{})
ch <- struct{}{}

使用

  • 直接定义变量,不会为字段赋初始值,所有字段都会赋默认值。
var m Member
  • 使用字面量创建变量
m := Member {
    1,
    "小明",
    "xiaoming@email.com",
    1,
}

m := Member {
    id: 2,
    "name": "小红",
}
  • 访问字段
fmt.Println(m.ID)

m.Name = "小花"
  • 指针结构体

结构体与数组一样都是值传递,比如当把数组或结构体作为实参传给函数的形参时,会复制一个副本。 所以为了提高性能,一般把结构体传给函数时使用指针结构体。

func main() {
    m := NewMember("小明")
    fmt.Println(m.name)
}

func NewMember(name string) *Member {
    return &Member{
        "name": name,
    }
}

可见性

在 Go 语言中,无论是结构体还是结构体内的字段又或是函数、常变量,它们的可见性都是由首字母的大小写决定的。

package member

// 结构体对外可见
type Member struct {
    ID     int        // 字段对外可见
    Name   string    // 字段对外可见
    Email  string    // 字段对外可见
    gender int        // 字段对外不可见
}

// 结构体对外可见
type member struct {
    ID     int        // 字段对外不可见
    Name   string    // 字段对外不可见
    Email  string    // 字段对外不可见
    gender int        // 字段对外不可见
}

两个一样的结构体,就因为结构体名不同,就会影响它们的可见性。 在代码中可以看到,如果一个结构体对外不可见,那么就算它的字段是大写的也不会对外可见。 值得一提的是,Go 语言支持(UTF-8 编码)中文变量、函数名,但是它们都是不可见的(中文是小写系列)。

变量 := 123
fmt.Println(变量)

Tags

在定义结构体字段时,可以使用反引号为结构体字段声明元信息,用于编译阶段关联到字段当中。

type Member struct {
    ID     int    `json:"id"`
    Name   string `json:"name"`
    Email  string `json:"email"`
    Gender int    `json:"gender"`
}

tag 的使用是函数定义的,上面定义的信息是标准库 encoding/json 编解码使用的。

type Member struct {
    ID     int    `json:"id, -"`
    Name   string `json:"name"`
    Email  string `json:"email"`
    Gender int    `json:"gender"`
}

这些信息不仅是一个字符串那么简单,因为其主要用于反射场景,reflect 包中提供了操作方法,所以写法也要遵循一定的规则。

Tag 本身是一个字符串,但字符串中却是:以空格分隔的 key:value 对。

  • key: 必须是非空字符串,字符串不能包含控制字符、空格、引号、冒号。
  • value: 以双引号标记的字符串
  • 冒号前后不能有空格
type Server struct {
    ServerName string `key1: "value1" key11:"value11"`
    ServerIP   string `key2: "value2"`
}

tag 的用途很广泛,常见一点就是 json 编解码,orm 框架等等。

基本概念

  1. 结构体是复合类型,无论是作为实参传递给函数时,还是赋值给其他变量,都是值传递。
  2. Go 是支持面向对象的,但却没有继承的概念,在结构体中,可以通过组合其他结构体来构建更复杂的结构体。
  3. 结构体不能包含自己,但可以包含自己的指针

方法

在 Go 语言中,将函数绑定到具体的类型中,则称该函数是该类型的方法。

func NewMember(name string) *Member {
    return &Member{
        "name": name,
    }
}

func (m *Member) setName(name string) {
    m.Name = name
}
  • 调用结构体的方法,与调用字段一样
    m := Member{}
    m.setName("小明")
    

组合

Go 语言的结构体没有继承的概念,但是有组合的概念,通过这种方式来达到代码复用效果。

组合可以理解为定义一个结构体中,其字段可以是其他的结构体,这样,不同的结构体就可以共用相同的字段。

例如,我们定义了一个名为Animal表示动物,如果我们想定义一个结构体表示猫,如:

type Animal struct {
    Name   string
}

func (a Animal) Run() {
    fmt.Println(a.Name + "is running")
}

func (a Animal) Eat() {
    fmt.Println(a.Name + "is eating")
}

type Cat struct {
    a Animal
}

func main() {
    c := Cat {
        a: Animal {
            Name:   "猫",
        },
    }
    fmt.Println(c.a.Name)
    c.a.Run()
}

匿名字段

上例中,Animal 作为 Cat 的字段时的变量名为 a,所以调用方法是 c.a.Run()

Go 语言支持直接将类型作为结构体的字段,而不需要取变量名,这种字段叫匿名字段。

type Lion struct {
    Animal // 匿名字段
}

func main(){
    var lion = Lion{
        Animal{
            Name:  "狮子",
        },
    }
    lion.Run()
    fmt.Println(lion.Name)
}
powered by Gitbook该文件修订时间: 2020-04-10 10:05:54

results matching ""

    No results matching ""

    results matching ""

      No results matching ""