day6 结构体和结构体的匿名成员

master
独孤伶俜 2022-11-20 17:05:06 +08:00
parent 575191ebde
commit fc1429756e
2 changed files with 160 additions and 0 deletions

68
src/study/day6/struct.go Normal file
View File

@ -0,0 +1,68 @@
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-结构体嵌入和匿名成员
}

View File

@ -0,0 +1,92 @@
package main
// 结构体嵌入和匿名成员
// 考虑一个二维的绘图程序,
// 提供了一个各种图形的库,例如矩形、椭圆形、星形和轮形等几何形状。
// 这里是其中两个的定义:
/**
type Circle struct {
X, Y, Radius int
}
type Wheel struct {
X, Y, Radius, Spokes int
}
*/
// 一个Circle代表的圆形类型包含了标准圆心的X和Y坐标信息
// 和一个Radius表示的半径信息。
// 一个Wheel轮形除了包含Circle类型所有的全部成员外
// 还增加了Spokes表示径向辐条的数量。
// 随着库中几何形状数量的增多,我们一定会注意到它们之间的相似和重复之处,
// 所以我们可能为了便于维护而将相同的属性独立出来:
/**
type Point struct {
X, Y int
}
type Circle struct {
Center Point
Radius int
}
type Wheel struct {
Circle Circle
Spokes int
}
*/
// 这样改动之后结构体类型变的清晰了,但是这种修改同时也导致了访问每个成员变得繁琐:
// Go语言有一个特性让我们只声明一个成员对应的数据类型而不指名成员的名字这类成员就叫匿名成员。
// 匿名成员的数据类型必须是命名的类型或指向一个命名的类型的指针。
// 下面的代码中Circle和Wheel各自都有一个匿名成员。
// 我们可以说Point类型被嵌入到了Circle结构体同时Circle类型被嵌入到了Wheel结构体。
type Point struct {
X, Y int
}
type Circle struct {
Point
Radius int
}
type Wheel struct {
Circle
Spokes int
}
func main() {
/**
var w Wheel
w.Circle.Center.X = 10
w.Circle.Center.Y = 20
w.Circle.Radius = 5
w.Spokes = 20
*/
// 得益于匿名嵌入的特性,我们可以直接访问叶子属性而不需要给出完整的路径:
var w Wheel
w.X = 10 // 等于w.Circle.Point.X
w.Y = 20 // 等于w.Circle.Point.Y
w.Radius = 5 // 等于w.Circle.Radius
w.Spokes = 20
// 同时上面注释中的全叶子写法也可以使用
w.Circle.Point.X = 10 // 同 w.X
w.Circle.Point.Y = 20 // 同 x.Y
// 不幸的是,结构体字面值并没有简短表示匿名成员的语法, 因此下面的语句都不能编译通过:
//w = Wheel{8, 8, 5, 20} // compile error: unknown fields
//w = Wheel{X: 8, Y: 8, Radius: 5, Spokes: 20} // compile error: unknown fields
// 结构体字面值必须遵循形状类型声明时的结构,所以我们只能用下面的两种语法,它们彼此是等价的:
w = Wheel{Circle{Point{10, 20}, 5}, 20}
w = Wheel{
Circle: Circle{
Point: Point{
X: 10,
Y: 20,
},
Radius: 5,
},
Spokes: 20,
}
}