mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2024-12-25 14:28:58 +00:00
ch4-04 header
This commit is contained in:
parent
44975014ea
commit
c3f72ea7a9
@ -1,6 +1,6 @@
|
|||||||
### 4.4.2. 結構體比較
|
### 4.4.2. 結構體比較
|
||||||
|
|
||||||
如果结构体的全部成员都是可以比较的,那么结构体也是可以比较的,那样的话两个结构体将可以使用==或!=运算符进行比较。相等比较运算符==将比较两个结构体的每个成员,因此下面两个比较的表达式是等价的:
|
如果結構體的全部成員都是可以比較的,那麽結構體也是可以比較的,那樣的話兩個結構體將可以使用==或!=運算符進行比較。相等比較運算符==將比較兩個結構體的每個成員,因此下面兩個比較的表達式是等價的:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
type Point struct{ X, Y int }
|
type Point struct{ X, Y int }
|
||||||
@ -11,7 +11,7 @@ fmt.Println(p.X == q.X && p.Y == q.Y) // "false"
|
|||||||
fmt.Println(p == q) // "false"
|
fmt.Println(p == q) // "false"
|
||||||
```
|
```
|
||||||
|
|
||||||
可比较的结构体类型和其他可比较的类型一样,可以用于map的key类型。
|
可比較的結構體類型和其他可比較的類型一樣,可以用於map的key類型。
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
type address struct {
|
type address struct {
|
||||||
|
135
ch4/ch4-04.md
135
ch4/ch4-04.md
@ -1,6 +1,139 @@
|
|||||||
## 4.4. 結構體
|
## 4.4. 結構體
|
||||||
|
|
||||||
TODO
|
結構體是一種聚合的數據類型,由零個或多個任意類型的值聚合成的實體。每個值稱爲結構體的成員。是用結構體的經典案例處理公司的員工信息,每個員工信息包含一個唯一的員工編號、員工的名字、家庭住址、出生日期、工作崗位、薪資、上級領導等等。所有的這些成員都需要綁定到一個實體,可以作爲一個整體單元被複製,作爲函數的參數或返迴值,或者是被存儲到數組中,等等。
|
||||||
|
|
||||||
|
下面兩個語句分别聲明了一個叫Employee的結構體類型,併且聲明了一個Employee類型的變量dilbert:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
type Employee struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
Address string
|
||||||
|
DoB time.Time
|
||||||
|
Position string
|
||||||
|
Salary int
|
||||||
|
ManagerID int
|
||||||
|
}
|
||||||
|
|
||||||
|
var dilbert Employee
|
||||||
|
```
|
||||||
|
|
||||||
|
dilbert結構體變量的成員可以通過點操作符訪問,比如dilbert.Name和dilbert.DoB。因爲dilbert是一個變量,它所有的成員也同樣是變量,我們可以對每個成員賦值:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
dilbert.Salary -= 5000 // demoted, for writing too few lines of code
|
||||||
|
```
|
||||||
|
|
||||||
|
或者是對成員取地址,然後通過指針訪問:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
position := &dilbert.Position
|
||||||
|
*position = "Senior " + *position // promoted, for outsourcing to Elbonia
|
||||||
|
```
|
||||||
|
|
||||||
|
點操作符也可以和指向結構體的指針一起工作:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
var employeeOfTheMonth *Employee = &dilbert
|
||||||
|
employeeOfTheMonth.Position += " (proactive team player)"
|
||||||
|
```
|
||||||
|
|
||||||
|
相當於下面語句
|
||||||
|
|
||||||
|
```Go
|
||||||
|
(*employeeOfTheMonth).Position += " (proactive team player)"
|
||||||
|
```
|
||||||
|
|
||||||
|
EmployeeByID函數將根據給定的員工ID返迴對應的員工信息結構體的指針。我們可以使用點操作符來訪問它里面的成員:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
func EmployeeByID(id int) *Employee { /* ... */ }
|
||||||
|
|
||||||
|
fmt.Println(EmployeeByID(dilbert.ManagerID).Position) // "Pointy-haired boss"
|
||||||
|
|
||||||
|
id := dilbert.ID
|
||||||
|
EmployeeByID(id).Salary = 0 // fired for... no real reason
|
||||||
|
```
|
||||||
|
|
||||||
|
後面的語句通過EmployeeByID返迴的結構體指針更新了Employee結構體的成員。如果將EmployeeByID函數的返迴值從`*Employee`指針類型改爲Employee值類型,那麽更新語句將不能編譯通過,因爲在賦值語句的左邊併不確定是一個變量。
|
||||||
|
|
||||||
|
通常一行對應一個結構體成員,成員的名字在前類型在後,不過如果相鄰的成員類型如果相同的話可以被合併到一行,就像下面的Name和Address成員那樣:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
type Employee struct {
|
||||||
|
ID int
|
||||||
|
Name, Address string
|
||||||
|
DoB time.Time
|
||||||
|
Position string
|
||||||
|
Salary int
|
||||||
|
ManagerID int
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
結構體成員的輸入順序也有重要的意義。我們也可以將Position成員合併(因爲也是字符串類型),或者是交換Name和Address出現的先後順序,那樣的話就是定義了不同的結構體類型。通常,我們隻是將相關的成員合併到一起。
|
||||||
|
|
||||||
|
如果結構體成員名字是以大寫字母開頭的,那麽該成員就是導出的;這是Go語言導出規則決定的。一個結構體可能同時包含導出和未導出的成員。
|
||||||
|
|
||||||
|
結構體類型往往是冗長的,因爲它的每個成員可能都會占一行。雖然我們每次都可以重寫整個結構體成員,但是重複會令人厭煩。因此,完整的結構體寫法通常隻在類型聲明語句的地方出現,就像Employee類型聲明語句那樣。
|
||||||
|
|
||||||
|
一個命名爲S的結構體類型將不能再包含S類型的成員:一個聚合的值不能包含它自身。(該限製同樣適應於數組。)但是S類型的結構體可以包含`*S`指針類型的成員,這可以讓我們創建遞歸的數據結構,比如鏈表和樹結構等。在下面的代碼中,我們使用一個二叉樹來實現一個插入排序:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
gopl.io/ch4/treesort
|
||||||
|
|
||||||
|
type tree struct {
|
||||||
|
value int
|
||||||
|
left, right *tree
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort sorts values in place.
|
||||||
|
func Sort(values []int) {
|
||||||
|
var root *tree
|
||||||
|
for _, v := range values {
|
||||||
|
root = add(root, v)
|
||||||
|
}
|
||||||
|
appendValues(values[:0], root)
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendValues appends the elements of t to values in order
|
||||||
|
// and returns the resulting slice.
|
||||||
|
func appendValues(values []int, t *tree) []int {
|
||||||
|
if t != nil {
|
||||||
|
values = appendValues(values, t.left)
|
||||||
|
values = append(values, t.value)
|
||||||
|
values = appendValues(values, t.right)
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
func add(t *tree, value int) *tree {
|
||||||
|
if t == nil {
|
||||||
|
// Equivalent to return &tree{value: value}.
|
||||||
|
t = new(tree)
|
||||||
|
t.value = value
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
if value < t.value {
|
||||||
|
t.left = add(t.left, value)
|
||||||
|
} else {
|
||||||
|
t.right = add(t.right, value)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
結構體類型的零值是每個成員都對是零值。通常會將零值作爲最合理的默認值。例如,在bytes.Buffer類型,結構體初始值就是一個隨時可用的空緩存,還有在第9章將會講到的sync.Mutex的零值也是有效的未鎖狀態。有時候這種零值可用的特性是自然獲得的,但是也有些類型需要一些額外的工作。
|
||||||
|
|
||||||
|
如果結構體沒有任何成員的話就是空結構體,寫作struct{}。它的大小爲0,也不包含任何信息,但是有時候依然是有價值的。有些Go語言程序員用map帶模擬set數據結構時,用它來代替map中布爾類型的value,隻是強調key的重要性,但是因爲節約的空間有限,而且語法比較複雜,所有我們通常避免避免這樣的用法。
|
||||||
|
|
||||||
|
```Go
|
||||||
|
seen := make(map[string]struct{}) // set of strings
|
||||||
|
// ...
|
||||||
|
if _, ok := seen[s]; !ok {
|
||||||
|
seen[s] = struct{}{}
|
||||||
|
// ...first time seeing s...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
{% include "./ch4-04-1.md" %}
|
{% include "./ch4-04-1.md" %}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user