## 4.4. 結構體

type Employee struct {
ID        int
Name      string
DoB       time.Time
Position  string
Salary    int
ManagerID int
}

var dilbert Employee


dilbert結構體變量的成員可以通過點操作符訪問，比如dilbert.Name和dilbert.DoB。因爲dilbert是一個變量，它所有的成員也同樣是變量，我們可以直接對每個成員賦值：

dilbert.Salary -= 5000 // demoted, for writing too few lines of code


position := &dilbert.Position
*position = "Senior " + *position // promoted, for outsourcing to Elbonia


var employeeOfTheMonth *Employee = &dilbert
employeeOfTheMonth.Position += " (proactive team player)"


(*employeeOfTheMonth).Position += " (proactive team player)"


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


type Employee struct {
ID            int
DoB           time.Time
Position      string
Salary        int
ManagerID     int
}


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
}


seen := make(map[string]struct{}) // set of strings
// ...
if _, ok := seen[s]; !ok {
seen[s] = struct{}{}
// ...first time seeing s...
}


### 4.4.1. 結構體面值

type Point struct{ X, Y int }

p := Point{1, 2}


anim := gif.GIF{LoopCount: nframes}


package p
type T struct{ a, b int } // a and b are not exported

package q
import "p"
var _ = p.T{a: 1, b: 2} // compile error: can't reference a, b
var _ = p.T{1, 2}       // compile error: can't reference a, b


func Scale(p Point, factor int) Point {
return Point{p.X * factor, p.Y * factor}
}

fmt.Println(Scale(Point{1, 2}, 5)) // "{5 10}"


func Bonus(e *Employee, percent int) int {
return e.Salary * percent / 100
}


func AwardAnnualRaise(e *Employee) {
e.Salary = e.Salary * 105 / 100
}


pp := &Point{1, 2}


pp := new(Point)
*pp = Point{1, 2}


### 4.4.2. 結構體比較

type Point struct{ X, Y int }

p := Point{1, 2}
q := Point{2, 1}
fmt.Println(p.X == q.X && p.Y == q.Y) // "false"
fmt.Println(p == q)                   // "false"


type address struct {
hostname string
port     int
}



### 4.4.3. 結構體嵌入和匿名成員

type Circle struct {
X, Y, Radius int
}

type Wheel struct {
X, Y, Radius, Spokes int
}


var w Wheel
w.X = 8
w.Y = 8
w.Spokes = 20


type Point struct {
X, Y int
}

type Circle struct {
Center Point
}

type Wheel struct {
Circle Circle
Spokes int
}


var w Wheel
w.Circle.Center.X = 8
w.Circle.Center.Y = 8
w.Spokes = 20


Go語言有一個特性讓我們隻聲明一個成員對應的數據類型而不指名成員的名字；這類成員就叫匿名成員。匿名成員的數據類型必鬚是命名的類型或指向一個命名的類型的指針。下面的代碼中，Circle和Wheel各自都有一個匿名成員。我們可以説Point類型被嵌入到了Circle結構體，同時Circle類型被嵌入到了Wheel結構體。

type Circle struct {
Point
}

type Wheel struct {
Circle
Spokes int
}


var w Wheel
w.X = 8            // equivalent to w.Circle.Point.X = 8
w.Y = 8            // equivalent to w.Circle.Point.Y = 8
w.Radius = 5       // equivalent to w.Circle.Radius = 5
w.Spokes = 20


w = Wheel{8, 8, 5, 20}                       // compile error: unknown fields
w = Wheel{X: 8, Y: 8, Radius: 5, Spokes: 20} // compile error: unknown fields


gopl.io/ch4/embed

w = Wheel{Circle{Point{8, 8}, 5}, 20}

w = Wheel{
Circle: Circle{
Point:  Point{X: 8, Y: 8},
},
Spokes: 20, // NOTE: trailing comma necessary here (and at Radius)
}

fmt.Printf("%#v\n", w)
// Output:
// Wheel{Circle:Circle{Point:Point{X:8, Y:8}, Radius:5}, Spokes:20}

w.X = 42

fmt.Printf("%#v\n", w)
// Output:
// Wheel{Circle:Circle{Point:Point{X:42, Y:8}, Radius:5}, Spokes:20}


w.X = 8 // equivalent to w.circle.point.X = 8