设为首页 加入收藏

TOP

Go基础系列:struct和嵌套struct(一)
2018-10-31 14:12:46 】 浏览:171
Tags:基础 系列 struct

struct

struct定义结构,结构由字段(field)组成,每个field都有所属数据类型,在一个struct中,每个字段名都必须唯一。

说白了就是拿来存储数据的,只不过可自定义化的程度很高,用法很灵活,Go中不少功能依赖于结构,就这样一个角色。

Go中不支持面向对象,面向对象中描述事物的类的重担由struct来挑,这种模式称为组合(composite)。面向对象中父类与子类、类与对象的关系是is a的关系,例如Horse is a Animal,Go中的组合则是外部struct与内部struct的关系、struct实例与struct的关系,它们是has a的关系。Go中通过struct的composite,可以"模仿"很多面向对象中的行为,它们很"像"。

定义struct

定义struct的格式如下:

type identifier struct {
    field1 type1
    field2 type2
    …
}
// 或者
type T struct { a, b int }

理论上,每个字段都是有具有唯一性的名字的,但如果确定某个字段不会被使用,可以将其名称定义为空标识符_来丢弃掉:

type T struct {
    _ string
    a int
}

每个字段都有类型,可以是任意类型,包括内置简单数据类型、其它自定义的struct类型、当前struct类型本身、接口、函数、channel等等。

如果某几个字段类型相同,可以缩写在同一行:

type mytype struct {
    a,b int
    c string
}

构造struct实例

定义了struct,就表示定义了一个数据结构,或者说数据类型,也或者说定义了一个类。总而言之,定义了struct,就具备了成员属性,就可以作为一个抽象的模板,可以根据这个抽象模板生成具体的实例,也就是所谓的"对象"。

例如:

type person struct{
    name string
    age int
}

// 初始化一个person实例
var p person

这里的p就是一个具体的person实例,它根据抽象的模板person构造而出,具有具体的属性name和age的值,虽然初始化时它的各个字段都是0值。换句话说,p是一个具体的人。

struct初始化时,会做默认的赋0初始化,会给它的每个字段根据它们的数据类型赋予对应的0值。例如int类型是数值0,string类型是"",引用类型是nil等。

因为p已经是初始化person之后的实例了,它已经具备了实实在在存在的属性(即字段),所以可以直接访问它的各个属性。这里通过访问属性的方式p.FIELD为各个字段进行赋值。

// 为person实例的属性赋值,定义具体的person
p.name = "longshuai"
p.age = 23

获取某个属性的值:

fmt.Println(p.name) // 输出"longshuai"

也可以直接赋值定义struct的属性来生成struct的实例,它会根据值推断出p的类型。

var p = person{name:"longshuai",age:23}

p := person{name:"longshuai",age:23}

// 不给定名称赋值,必须按字段顺序
p := person{"longshuai",23}

p := person{age:23}
p.name = "longshuai"

如果struct的属性分行赋值,则必须不能省略每个字段后面的逗号",",否则就会报错。这为未来移除、添加属性都带来方便:

p := person{
    name:"longshuai",
    age:23,     // 这个逗号不能省略
}

除此之外,还可以使用new()函数或&TYPE{}的方式来构造struct实例,它会为struct分配内存,为各个字段做好默认的赋0初始化。它们是等价的,都返回数据对象的指针给变量,实际上&TYPE{}的底层会调用new()。

p := new(person)
p := &person{}

// 生成对象后,为属性赋值
p.name = "longshuai"
p.age = 23

使用&TYPE{}的方式也可以初始化赋值,但new()不行:

p := &person{
    name:"longshuai",
    age:23,
}

选择new()还是选择&TYPE{}的方式构造实例?完全随意,它们是等价的。但如果想要初始化时就赋值,可以考虑使用&TYPE{}的方式。

struct的值和指针

下面三种方式都可以构造person struct的实例p:

p1 := person{}
p2 := &person{}
p3 := new(person)

但p1和p2、p3是不一样的,输出一下就知道了:

package main

import (
    "fmt"
)

type person struct {
    name string
    age  int
}

func main() {
    p1 := person{}
    p2 := &person{}
    p3 := new(person)
    fmt.Println(p1)
    fmt.Println(p2)
    fmt.Println(p3)
}

结果:

{ 0}
&{ 0}
&{ 0}

p1、p2、p3都是person struct的实例,但p2和p3是完全等价的,它们都指向实例的指针,指针中保存的是实例的地址,所以指针再指向实例,p1则是直接指向实例。这三个变量与person struct实例的指向关系如下:

 变量名      指针     数据对象(实例)
-------------------------------
p1(addr) -------------> { 0}
p2 -----> ptr(addr) --> { 0}
p3 -----> ptr(addr) --> { 0}

所以p1和ptr(addr)保存的都是数据对象的地址,p2和p3则保存ptr(addr)的地址。通常,将指向指针的变量(p1、p2)直接称为指针,将直接指向数据对象的变量(p1)称为对象本身,因为指向数据对象的内容就是数据对象的地址,其中ptr(addr)和p1保存的都是实例对象的地址。

尽管一个是数据对象值,一个是指针,它们都是数据对象的实例。也就是说,p1.namep2.name都能访问对应实例的属性。

var p4 *person呢,它是什么?该语句表示p4是一个指针,它的指向对象是person类型的,但因为它是一个指针,它将初始化为nil,即表示没有指向目标。但已经明确表示了,p4所指向的是一个保存数据对象地址的指针。也就是说,目前为止,p4的指向关系如下:

p4 -> ptr(nil)

既然p4是一个指针,那么可以将&person{}new(person)赋值给p4。

var p4 *person
p4 = &per
编程开发网
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Go基础系列:struct的导出和暴露.. 下一篇Go基础系列:defer、panic和recov..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

array(4) { ["type"]=> int(8) ["message"]=> string(24) "Undefined variable: jobs" ["file"]=> string(32) "/mnt/wp/cppentry/do/bencandy.php" ["line"]=> int(214) }