mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-11 22:53:43 +08:00
统一术语和格式
This commit is contained in:
@@ -2,6 +2,6 @@
|
||||
|
||||
Go通过类型别名(alias types)或结构体的形式支持用户自定义类型,或者叫定制类型。一个带属性的结构体试图表示一个现实世界中的实体。结构体是复合类型(omposite types),当需要定义一个类型,它由一系列属性组成,每个属性都有自己的类型和值的时候,就应该使用结构体,它把数据聚集在一起。然后可以访问这些数据,就好像它是一个独立实体的一部分。
|
||||
|
||||
组成结构体类型的那些数据称为 *成员(fields)*。一个成员有一个类型和一个名字;在一个结构体中,成员名字必须是唯一的。
|
||||
组成结构体类型的那些数据称为 *字段(fields)*。一个字段有一个类型和一个名字;在一个结构体中,字段名字必须是唯一的。
|
||||
|
||||
结构体的概念在软件工程上旧的术语叫ADT(抽象数据类型:Abstract Data Type),在一些老的编程语言中叫*记录(Record)*,比如Cobol,在C家族的编程语言中它也存在,并且名字也是*struct*,在面向对象的编程语言中,跟一个无方法的轻量级类一样。不过因为Go语言中没有类的概念,因此在Go中结构体有着更为重要的地位。
|
@@ -12,9 +12,9 @@ type identifier struct {
|
||||
|
||||
`type T struct {a, b int}`也是合法的语法,它更适用于简单的结构体。
|
||||
|
||||
这个结构体里的成员都有*名字*,像field1,field2等,如果成员在代码中从来也不会被用到,那么可以命名它为*_*。
|
||||
这个结构体里的字段都有*名字*,像field1,field2等,如果字段在代码中从来也不会被用到,那么可以命名它为*_*。
|
||||
|
||||
结构体的成员可以是任何类型,甚至是结构体本身(参考[10.5](10.5.md)),可以是函数或者接口(参考第11章)。可以声明结构体类型的一个变量,然后给它的成员像下面这样赋值:
|
||||
结构体的字段可以是任何类型,甚至是结构体本身(参考[10.5](10.5.md)),可以是函数或者接口(参考第11章)。可以声明结构体类型的一个变量,然后给它的字段像下面这样赋值:
|
||||
|
||||
```go
|
||||
var s T
|
||||
@@ -22,7 +22,7 @@ s.a = 5
|
||||
s.b = 8
|
||||
```
|
||||
|
||||
数组可以看作是一种结构体类型,不过它使用下标而不是具名的成员。
|
||||
数组可以看作是一种结构体类型,不过它使用下标而不是具名的字段。
|
||||
|
||||
**使用new**
|
||||
|
||||
@@ -33,7 +33,7 @@ var t *T
|
||||
t = new(T)
|
||||
```
|
||||
|
||||
写这条语句的惯用方法是:`t := new(T)`,变量`t`是一个指向`T`的指针,此时结构体成员的值是它们所属类型的零值。
|
||||
写这条语句的惯用方法是:`t := new(T)`,变量`t`是一个指向`T`的指针,此时结构体字段的值是它们所属类型的零值。
|
||||
|
||||
声明`var t T`也会给`t`分配内存,并零值化内存,但是这个时候`t`是类型T。在这两种方式中,`t`通常被称做类型T的一个实例(instance)或对象(Object)。
|
||||
|
||||
@@ -71,11 +71,11 @@ func main {
|
||||
|
||||
使用fmt.Println打印一个结构体的默认输出可以很好的显示它的内容,类似使用*%v*选项。
|
||||
|
||||
就像在面向对象语言所作的那样,可以使用逗号符给成员赋值:` structname.fieldname = value `。
|
||||
就像在面向对象语言所作的那样,可以使用逗号符给字段赋值:` structname.fieldname = value `。
|
||||
|
||||
同样的,使用逗号符可以获取结构体成员的值:` structname.fieldname `。
|
||||
同样的,使用逗号符可以获取结构体字段的值:` structname.fieldname `。
|
||||
|
||||
在Go语言中这叫*选择器(selector)*。无论变量是一个结构体类型还是一个结构体类型指针,都使用同样的*选择器符(selector-notation)*来引用结构体的成员:
|
||||
在Go语言中这叫*选择器(selector)*。无论变量是一个结构体类型还是一个结构体类型指针,都使用同样的*选择器符(selector-notation)*来引用结构体的字段:
|
||||
|
||||
```go
|
||||
type myStruct struct { i int }
|
||||
@@ -99,7 +99,7 @@ p.i
|
||||
ms := struct1{10, 15.5, "Chris"}
|
||||
```
|
||||
|
||||
混合字面量语法(composite literal syntax)`&struct1{a, b, c}`是一种简写,底层仍然会调用`new ()`,这里值的顺序必须按照成员顺序来写。在下面的例子中能看到可以通过在值的前面放上成员名来初始化成员的方式。表达式`new(Type)` 和`&Type{}`是等价的。
|
||||
混合字面量语法(composite literal syntax)`&struct1{a, b, c}`是一种简写,底层仍然会调用`new ()`,这里值的顺序必须按照字段顺序来写。在下面的例子中能看到可以通过在值的前面放上字段名来初始化字段的方式。表达式`new(Type)` 和`&Type{}`是等价的。
|
||||
|
||||
时间间隔(开始和结束时间以秒为单位)是使用结构体的一个典型例子:
|
||||
|
||||
@@ -118,9 +118,9 @@ intr := Interval(end:5, start:1) (B)
|
||||
intr := Interval(end:5) (C)
|
||||
```
|
||||
|
||||
在(A)中,值必须以成员在结构体定义时的顺序给出,*&*不是必须的。(B)显示了另一种方式,成员名加一个冒号放在值的前面,这种情况下值的顺序不必一致,并且某些成员还可以被忽略掉,就像(C)中那样。
|
||||
在(A)中,值必须以字段在结构体定义时的顺序给出,*&*不是必须的。(B)显示了另一种方式,字段名加一个冒号放在值的前面,这种情况下值的顺序不必一致,并且某些字段还可以被忽略掉,就像(C)中那样。
|
||||
|
||||
结构体类型和成员的命名遵循可见性规则([4.2](4.2.md)),一个导出的结构体类型中有些成员是导出的,另一些不是,这是可能的。
|
||||
结构体类型和字段的命名遵循可见性规则([4.2](4.2.md)),一个导出的结构体类型中有些字段是导出的,另一些不是,这是可能的。
|
||||
|
||||
下图说明了结构体类型实例和一个指向它的指针的内存布局:
|
||||
|
||||
@@ -186,7 +186,7 @@ func main() {
|
||||
The name of the person is CHRIS WOODWARD
|
||||
The name of the person is CHRIS WOODWARD
|
||||
|
||||
在上面例子的第二种情况中,可以直接通过指针,像`pers2.lastName="Woodward"`这样给结构体成员赋值,没有像C++中那样需要使用`->`操作符,Go会自动做这样的转换。
|
||||
在上面例子的第二种情况中,可以直接通过指针,像`pers2.lastName="Woodward"`这样给结构体字段赋值,没有像C++中那样需要使用`->`操作符,Go会自动做这样的转换。
|
||||
|
||||
注意也可以通过解指针的方式来设置值:`(*pers2).lastName = "Woodward"`
|
||||
|
||||
@@ -209,7 +209,7 @@ type Rect2 struct {Min, Max *Point }
|
||||
|
||||

|
||||
|
||||
这块的`data`成员用于存放有效数据(比如float64),`su`指针指向后继节点。
|
||||
这块的`data`字段用于存放有效数据(比如float64),`su`指针指向后继节点。
|
||||
|
||||
Go代码:
|
||||
|
||||
|
@@ -20,9 +20,9 @@ type innerS struct {
|
||||
}
|
||||
|
||||
type outerS struct {
|
||||
b int
|
||||
c float32
|
||||
int // anonymous field
|
||||
b int
|
||||
c float32
|
||||
int // anonymous field
|
||||
innerS //anonymous field
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ func main() {
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
outer.b is: 6
|
||||
outer.c is: 7.500000
|
||||
outer.int is: 60
|
||||
@@ -95,8 +96,8 @@ func main() {
|
||||
|
||||
当两个成员拥有相同的名字(可能是继承来的名字)时该怎么办呢?
|
||||
|
||||
* 外层名字会覆盖内层名字,这提供了一种重载成员或方法的方式
|
||||
* 如果相同的名字在同一级别出现了两次,如果这个名字被程序使用了,将会引发一个错误(不使用没关系)。没有办法来解决这种问题引起的二义性,必须由程序员自己修正。
|
||||
1) 外层名字会覆盖内层名字,这提供了一种重载成员或方法的方式
|
||||
2) 如果相同的名字在同一级别出现了两次,如果这个名字被程序使用了,将会引发一个错误(不使用没关系)。没有办法来解决这种问题引起的二义性,必须由程序员自己修正。
|
||||
|
||||
例子:
|
||||
|
||||
@@ -108,14 +109,14 @@ type C struct {A; B}
|
||||
var c C;
|
||||
```
|
||||
|
||||
规则2:使用c.a是错误的,到底是c.A.a还是c.B.a呢?会导致编译器错误:*ambiguous DOT reference c.a disambiguate with either c.A.a or c.B.a*
|
||||
规则2:使用c.a是错误的,到底是c.A.a还是c.B.a呢?会导致编译器错误:*ambiguous DOT reference c.a disambiguate with either c.A.a or c.B.a*
|
||||
|
||||
```go
|
||||
type D struct {B; b float32}
|
||||
var d D;
|
||||
```
|
||||
|
||||
规则1:使用d.b是没问题的:它是float32,而不是B的b。如果想要内层的b可以通过d.B.b得到。
|
||||
规则1:使用d.b是没问题的:它是float32,而不是B的b。如果想要内层的b可以通过d.B.b得到。
|
||||
|
||||
## 链接
|
||||
- [目录](directory.md)
|
||||
|
@@ -89,7 +89,7 @@
|
||||
- 10.2 [使用工厂方法创建结构体实例](10.2.md)
|
||||
- 10.3 [使用自定义包中的结构体](10.3.md)
|
||||
- 10.4 [带标签的结构体](10.4.md)
|
||||
- 10.5 [匿名成员和内嵌结构体](10.5.md)
|
||||
- 10.5 [匿名字段和内嵌结构体](10.5.md)
|
||||
- 第11章:接口(interface)与反射(reflection)
|
||||
|
||||
## 第三部分:Go 高级编程
|
||||
|
Reference in New Issue
Block a user