docs: 结构体、值接收者、构造函数

This commit is contained in:
Shikong 2021-10-02 16:17:01 +08:00
parent 78decca578
commit 2444f78870
4 changed files with 204 additions and 0 deletions

View File

@ -0,0 +1,26 @@
package main
import "fmt"
type Person struct {
Name string
age int
}
// 构造函数 约定成俗 使用 New 开头
// 返回结构体 因结构体为值类型 赋值的时候都是 拷贝 内存开销大
// 返回结构体指针 当结构体比较大时 使用结构体指针 减少内存开销
func NewPerson(name string, age int) *Person {
return &Person{
name,
age,
}
}
func main() {
p1 := NewPerson("张三", 20)
p2 := NewPerson("李四", 18)
fmt.Printf("%T %#v\n", p1, p1)
fmt.Printf("%T %#v\n", p2, p2)
}

92
base/struct/main.go Normal file
View File

@ -0,0 +1,92 @@
package main
import (
"fmt"
"time"
)
// 结构体
// Golang 中 通过 struct 实现面向对象
// 结构体 是 值类型
type Person struct {
Age int
Name string
Gender string
Hobby []string
}
// golang 中 函数参数都是副本
func change(p Person) {
// 修改 的是 副本的 Gender
p.Gender = "女"
}
func change2(p *Person) {
// 根据内存地址 找到 原变量 并修改
// (*p).Gender = "女"
// 语法糖 自动根据指针找到变量
p.Gender = "女"
}
func main() {
// 声明一个 person 类型的变量
var p1 Person
// 通过字段赋值
p1.Name = "于谦"
p1.Age = time.Now().Year() - 1969
p1.Gender = "男"
p1.Hobby = []string{"抽烟", "喝酒", "烫头"}
// 访问 Name 字段
fmt.Println(p1.Name)
fmt.Printf("type: %T value: %#v\n", p1, p1)
// 匿名结构体 一般用于临时场景
var s struct {
name string
age int
}
s.name = "s"
s.age = 100
fmt.Printf("type: %T value: %#v\n", s, s)
fmt.Println("=========================================================")
change(p1)
fmt.Printf("type: %T value: %#v\n", p1, p1)
change2(&p1)
fmt.Printf("type: %T value: %#v\n", p1, p1)
fmt.Println("=========================================================")
var p2 = new(Person)
(*p2).Name = "person2"
p2.Age = 10086
fmt.Printf("type: %T value: %#v\n", p2, p2)
fmt.Printf("内存地址: %p\n", p2)
fmt.Printf("p2 的 内存地址: %p\n", &p2)
fmt.Println("=========================================================")
// 声明并初始化 结构体
var p3 = Person{Name: "张三", Gender: "男"}
fmt.Printf("type: %T value: %#v\n", p3, p3)
// 使用值列表的形式初始化 结构体
// 值的 顺序 要和 结构体定义的 字段顺序 一致
var p4 = Person{20, "李四", "男", []string{}}
fmt.Printf("type: %T value: %#v\n", p4, p4)
fmt.Println("=========================================================")
// 声明并初始化 结构体 指针 (常用)
var p5 = &Person{Name: "王五", Gender: "男"}
fmt.Printf("type: %T value: %#v\n", p5, p5)
// 使用值列表的形式初始化 结构体指针
// 值的 顺序 要和 结构体定义的 字段顺序 一致
var p6 = &Person{20, "赵六", "男", []string{}}
fmt.Printf("type: %T value: %#v\n", p6, p6)
}

View File

@ -0,0 +1,23 @@
package main
import "fmt"
// 结构体占用一块连续的内存空间
type memory struct {
a int8 // 8bit => 1byte
b int8
c int64 // 连续的类型不同时 golang 会进行内存对齐 便于快速寻址
}
func main() {
m := memory{
a: 10,
b: 20,
c: 30,
}
fmt.Printf("%T\t%p\n", m.a, &m.a)
fmt.Printf("%T\t%p\n", m.b, &m.b)
fmt.Printf("%T\t%p\n", m.c, &m.c)
}

View File

@ -0,0 +1,63 @@
package main
import "fmt"
// golang 中 如果
// 标识符 首字母为大写 则对外部包可见(类似 java 中 的 public)
// 反之不可见(类似 java 中的 private)
// Person 人
type Person struct {
name string
age int
}
// 作用于 特定类型 的 函数
// 接收者 表示的是 特定的类型变量, 常用类型首字母小写表示 不建议使用 this 或 self
// func (接收者变量 接收者类型) 方法名(参数...) (返回值...) { ... }
func (p Person) Say() {
fmt.Printf("%s: My name is %s, %d years old\n", p.name, p.name, p.age)
}
// AddAge
// 值接收者 传递的是 拷贝 的 值对象
func (p Person) AddAge() {
p.age++
}
// AddAge2
// 指针接收者 传递的是 对象 的 内存地址
// 使用场景:
// 需要修改接收者中的值
// 接收者是拷贝代价比较大的大对象
// 保证一致性, 如果某个方法使用了指针接收者 那么其他的方法也应该使用指针接收者
func (p *Person) AddAge2() {
// 原始写法
//(*p).age++
// 语法糖
p.age++
}
func NewPerson(name string, age int) *Person {
return &Person{
name,
age,
}
}
func main() {
p1 := NewPerson("张三", 20)
p1.Say()
fmt.Println("=========================================================")
p1.AddAge()
p1.Say()
fmt.Println("=========================================================")
p1.AddAge2()
p1.Say()
}