package main

import (
	"fmt"
	"time"
)

// 结构体是一种聚合的数据类型，是由零个或多个任意类型的值聚合成的实体。
// 每个值称为结构体的成员

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

var dilbert Employee

func main() {
	// dilbert结构体变量的成员可以通过点操作符访问，
	// 比如dilbert.Name和dilbert.DoB。
	// 因为dilbert是一个变量，它所有的成员也同样是变量，我们可以直接对每个成员赋值：
	dilbert.Salary = 5000
	fmt.Println(dilbert.Salary)

	// 或者对其成员取地址，通过指针访问
	dilbert.Name = "小明"
	pname := &dilbert.Name
	*pname = "张三"
	fmt.Println(dilbert.Name, *pname)

	// .操作符也可以和指向结构体变量的指针一起使用
	var pdilbert *Employee = &dilbert
	pdilbert.ID = 10001
	fmt.Println(pdilbert.ID, pdilbert.Name)
	// 相当于
	(*pdilbert).ID = 1001
	fmt.Println(pdilbert.ID, pdilbert.Name)

	// 结构体可以作为函数的参数和返回值
	// 例如，这个Scale函数将Point类型的值缩放后返回
	var scale = func(p Point, factor int) Point {
		return Point{X: p.X * factor, Y: p.Y * factor}
	}
	point1 := Point{X: 100, Y: 200}
	fmt.Println(scale(point1, 4))

	// 较大的结构体通常会用指针的方式传入和返回
	scale1 := func(pPoint *Point, factor int) *Point {
		pPoint.X, pPoint.Y = pPoint.X*factor, pPoint.Y*factor
		return pPoint
	}
	fmt.Println(*(scale1(&point1, 2)))

	// 与C语言类似，go中的函数参数和返回值的传递都是值拷贝传递，
	// 所以要在函数内部修改原结构体变量值时，结构体变量指针的传递时必须的

	// 因为结构体通常通过指针处理，可以用下面的写法来创建并初始化一个结构体变量，并返回结构体的地址
	pPoint := &Point{X: 10, Y: 20} // pPoint变量的类型为*Point型
	fmt.Printf("%T %[1]v \n", pPoint)

	// https://golang-china.github.io/gopl-zh/ch4/ch4-04.html#443-结构体嵌入和匿名成员

}
