Files
the-way-to-go_ZH_CN/eBook/10.1.md
2015-06-05 13:54:41 +08:00

4.5 KiB
Raw Blame History

10.1 结构体定义

结构体定义的一般方式如下:

```go
type identifier struct {
    field1 type1
    field2 type2
    ...
}
```

type T struct {a, b int}也是合法的语法,它更适用于简单的结构体。

这个结构体里的成员都有名字(names)像field1field2等如果成员在代码从来也不会被用到那么可以命名为*_*。

成员可以是任何类型,甚至是结构体本身(参考10.5可以是函数或者接口参考第11章。可以定义结构体类型的一个变量然后给它的成员像下面这样赋值

```go
var s T
s.a = 5
s.b = 8
```

数组可以看作是一种结构体类型,不过它使用下标而不是命名的成员。

使用new

使用new函数给一个新的结构体变量分配内存,它返回指向已分配内存的指针:var t *T = new(T),如果需要可以把这条语句放在不同的行(比如定义是包范围的,但是分配却没有必要在开始就做)。

```go
var t *T
t = new(T)
```

写这条语句的惯用法是:t := new(T),变量t是一个指向T的指针,此时结构体成员的值是它们所属类型的零值。

声明var t T也会给t分配内存并零值化内存但是这个时候t是类型T。在这两种方式中t通常被称做类型T的一个实例(instance)或对象(Object)。

Listing 10.1—structs_fields.go给出了一个非常简单的例子:

package main
import "fmt"

type struct1 struct {
    i1  int
    f1  float32
    str string
}

func main {
    ms := new(struct1)
    ms.i1 = 10
    ms.f1 = 15.5
    ms.str= "Chris"

    fmt.Printf("The int is: %d\n", ms.i1)
    fmt.Printf("The float is: %f\n", ms.f1)
    fmt.Printf("The string is: %s\n", ms.str)
    fmt.Println(ms)
}

输出:

The int is: 10
The float is: 15.500000
The string is: Chris
&{10 15.5 Chris}

使用fmt.Println打印一个结构体的默认输出可以很好的显示它的内容类似使用*%v*选项。

可以通过逗号符给成员赋不同的值,就像在面向对象语言中那样:structname.fieldname = value

使用同样的逗号符可以获取结构体成员的值:structname.fieldname

在Go中这叫选择器(selector)。无论变量是一个结构体类型还是一个结构体类型指针,都使用同样的选择器符(selector-notation)来引用结构体的成员:

```go
type myStruct struct { i int }
var v myStruct    // v has struct type
var p *myStruct   // p is a pointer to a struct
v.i 
p.i
```

初始化一个结构体实例(一个结构体字面量struct-literal)的更简短和惯用的方式如下:

```go
    ms := &struct1{10, 15.5, "Chris"}
    // 此时ms的类型是 *struct1
```

或者:

```go
    var mt struct1
    ms := struct1{10, 15.5, "Chris"}
```

混合字面量语法(composite literal syntax) &struct1{a, b, c} 是一种简写,底层仍然会调用 new (),这里值的顺序必须按照成员顺序来写。在下面的例子中能看到可以通过在值的前面放上成员名来初始化值。表达式 new(Type) &Type{}是等价的。

结构体的典型例子是一个时间间隔(开始和结束时间以秒为单位)

```go
type Interval struct {
    start int
    end   int
}
```

初始化方式:

```go
intr := Interval(0, 3)            (A)
intr := Interval(end:5, start:1)  (B)
intr := Interval(end:5)           (C)
```

A中值必须以成员在结构体定义时的顺序给出*&*不是必须的。B显示了另一种方式成员名加上一个冒号在值的前面这种情况下值的顺序不必一致并且某些成员还可以被忽略掉就像C那样。

结构体类型和成员的命名遵循可见性规则(4.2,一个导出的结构体类型中有些成员是导出的,另一些不是,这是可能的。

下图说明了结构体类型实例和一个指向它的指针的内存布局:

```go
type Point struct { x, y int }
```

使用new初始化

作为结构体字面量初始化:

练习9.2

通过使用 unsafe 包中的方法来测试你电脑上一个整型变量占用多少个字节。

链接