Go 基础之结构体
Go 5
递归函数
package main
import "fmt"
// 递归函数,一定要有一个明确的退出条件
// 计算n的阶乘
func f1(n int) int {
if n > 0 {
res := n * f1(n-1)
return res
} else {
return 1
}
}
// 台阶有n阶,一个人上台阶,可以一次上1阶,可以一次上2阶,也可以一次上3阶,问上这个n级的台阶一共有多少种走法?
func fx(n int) int {
switch {
case n == 1:
return 1
case n == 2:
return 2
case n == 3:
return 4
case n >= 4:
return fx(n-1) + fx(n-2) + fx(n-3)
default:
return 0
}
}
func main() {
// fmt.Println(f1(3)) // 5*4*3*2
fmt.Println(fx(5))
}
type
// 自定义类型和类型别名
type myint int // 自定义类型
type yourint = int // 类型别名
func main() {
var n myint
n = 100
fmt.Println(n)
fmt.Printf("%T\n", n)
c := "中"
d := '中'
fmt.Println(c, d)
fmt.Printf("%T--%T\n", c, d)
}
结构体(struct)
package main
import "fmt"
// 结构体
type mytp struct {
t1 int
t2 string
t3 []int
}
type person struct {
name string
age int
gender string
hobby []string
tt mytp
}
func main() {
// 声明一个person类型的p
var p1 person
// 通过字段去赋值
p1.name = "hina"
p1.age = 18
p1.gender = "男"
p1.hobby = []string{"唱", "跳", "rap", "篮球"}
p1.tt.t1 = 111
p1.tt.t2 = "xixix"
p1.tt.t3 = []int{1, 2, 3}
fmt.Println(p1)
}
匿名结构体
// 匿名结构体:多用于临时场景
var s struct {
x string
y int
}
s.x = "xxx"
s.y = 111
fmt.Printf("%T---%v\n", s, s)
结构体指针
package main
import (
"fmt"
)
type person struct {
name, gender string
}
// Go语言中函数参数永远是拷贝
func f(x person) {
x.gender = "ffff" // 修改的是副本的gender
}
func f2(x *person) {
// (*x).gender = "ffff" // 修改那个内存地址的变量的值
x.gender = "ffff" // 语法糖,Go中不能对指针做操作,所有会自动添加*x
}
func main() {
// var p person
// p.name = "hina"
// p.gender = "male"
// f(p)
// fmt.Println(p)
// f2(&p)
// fmt.Println(p)
// 结构体指针一
// var p2 = new(person)
// fmt.Printf("%T\n", p2)
// fmt.Printf("%p\n", p2) // p2保存的值就是一个内存地址
// fmt.Printf("%p\n", &p2) // p2的内存地址
// 结构体指针二
// 2.1 key-value初始化
var p3 = &person{
name: "hii",
gender: "xxx",
}
fmt.Printf("%#v\n", p3)
// 2.2使用值列表的形式初始化,值得顺序要和结构体定义时字段顺序一致
p4 := &person{
"hnnn",
"ffff",
}
fmt.Printf("%#v\n", p4)
}
结构体占用连续内存
package main
import "fmt"
// 结构体占用一块连续的内存空间
type x struct {
// a int8 // 8bits = 1bytes
// b int8
// c int8
a, b, c int8
d string
}
func main() {
m := x{
a: int8(10),
b: int8(20),
c: int8(30),
d: "hina",
}
fmt.Printf("%p\n", &m.a)
fmt.Printf("%p\n", &m.b)
fmt.Printf("%p\n", &m.c)
fmt.Printf("%p\n", &m.d)
}
构造函数:返回一个结构体变量的函数
结构体是值类型,赋值的时候都是拷贝
package main
import "fmt"
// 构造函数
type person struct {
name string
age int
}
// 构造函数
// 返回的是结构体还是结构体指针
// 当结构体比较大的时候尽量使用结构体指针,减少程序的内存消耗
func newperson(name string, age int) *person {
return &person{
name: name,
age: age,
}
}
func main() {
p1 := newperson("hina", 20)
p2 := newperson("rui", 14)
fmt.Println(p1, p2)
}
方法
package main
import "fmt"
type dog struct {
name string
}
func newdog(name string) dog {
return dog{
name: name,
}
}
// 方法是作用域特定类型的函数
// 接受者表示的是调用该方法的具体类型变量,多用类型名首字母小写表示
// 不使用*的话会将d的一个复制体传过来
func (d dog) wang() {
fmt.Printf("%p\n", &d)
fmt.Printf("%s:www\n", d.name)
}
func main() {
d1 := newdog("zzz")
fmt.Printf("%p\n", &d1)
d1.wang()
}
值接受者和指针接受者
拷贝和传递的意思
什么时候需要使用指针接受者
- 需要修改接受者中的值
- 接受者占用内存太大
- 保证一致性,如果有某个方法使用了指针接受者,那么其他方法也应该使用指针接受者
给自定义类型加方法(给int加方法)
package main
import "fmt"
// 给自定义类型加方法
// 不能给别的包里的类型添加方法,只能给自己的包里加
type myInt int
func (m myInt) hello() {
fmt.Println("我是一个int")
}
func main() {
m := myInt(100)
m.hello()
}
结构体常见问题
package main
import "fmt"
type person struct {
name string
age int
}
func main() {
// 结构体初始化
var p person // 声明一个person的变量p
p.name = "hina"
p.age = 18
fmt.Println(p)
// 值键值对初始化
p1 := person{
name: "rui",
age: 18,
}
fmt.Println(p1)
p2 := newperson("lem", 12)
fmt.Println(p2)
p3 := newperson1("emt", 13)
fmt.Println(p3)
}
func newperson(name string, age int) person {
return person{
name: name,
age: age,
}
}
func newperson1(name string, age int) *person {
return &person{
name: name,
age: age,
}
}
结构体的匿名字段
package main
// 匿名字段
// 字段比较少也比较简单的常见
// 不常用!!!
type person struct {
string
int
}
func main() {
p1 := person{
"hina",
14,
}
}
嵌套结构体
匿名嵌套结构体
package main
import "fmt"
// 嵌套结构体
type address struct {
addr, city string
}
type workplace struct {
addr, city string
}
type person struct {
name string
age int
address // 匿名嵌套结构体
// workplace
}
type conpany struct {
name string
address
}
func main() {
p1 := person{
name: "hina",
age: 18,
address: address{
addr: "江苏",
city: "南京",
},
}
fmt.Println(p1)
fmt.Println(p1.name, p1.address.addr, p1.address.city)
fmt.Println(p1.city) // 现在自己结构体找这个字段,找不到就去匿名嵌套的结构体的字段
}
匿名嵌套结构体的字段冲突
将字段写全
结构体的继承
package main
import "fmt"
// 结构体模拟实现其他语言的继承
type animal struct {
name string
}
// 给animal实现一个动的方法
func (a *animal) move() {
fmt.Printf("%s会动\n", a.name)
}
// dog类
type dog struct {
feet int8
animal // animal拥有的属性和方法dog全都有
}
// 给dog实现叫的方法
func (d *dog) wang() {
fmt.Printf("%s:汪汪汪~\n", d.name)
}
func main() {
d1 := dog{
feet: 4,
animal: animal{
name: "teddy",
},
}
fmt.Println(d1)
d1.wang()
d1.move()
}
结构体与json
package main
import (
"encoding/json"
"fmt"
)
// 结构体与json
// 1.序列化:把Go语言中结构体变量——> json格式字符串
// 2.反序列化:json格式的字符串——> Go语言中能够识别的结构体变量
type person struct {
Name string `json:"name" db:"name" ini:"name"`
Age int `json:"age"`
}
func main() {
p1 := person{
Name: "hina",
Age: 18,
}
// 序列化
b, err := json.Marshal(p1)
if err != nil {
fmt.Printf("序列化错误,%s\n", err)
return
}
fmt.Println(string(b))
// fmt.Printf("%#v\n", string(b))
// 反序列化
str := `{"name":"lem","age":111}`
var p2 person
json.Unmarshal([]byte(str), &p2) // 传指针是为了能在函数内部去修改p2的值
fmt.Printf("%#v\n", p2)
}
函数版学生信息管理系统
package main
import (
"fmt"
"os"
)
/*
学生管理系统
写一个系统能够查看\新增\删除\编辑学生
*/
type student struct {
id int64
name string
}
func main() {
for {
// 1.打印菜单
fmt.Println("学生管理系统")
fmt.Println(`
0. 退出
1. 查看所有学生
2. 新增学生
3. 删除学生
`)
fmt.Println("请输入指令:")
// 2.等待用户选择
var choice int
fmt.Scanln(&choice)
// fmt.Println(choice)
// 3.执行对应的函数
switch choice {
case 1:
showstu()
case 2:
addstu()
case 3:
delstu()
case 0:
os.Exit(1) // 退出、break退出的是switch
default:
fmt.Println("无效指令")
}
}
}
var (
allstu = make(map[int64]*student) // 初始化(开辟内存空间)
)
func newstu(id int64, name string) *student {
return &student{
id: id,
name: name,
}
}
func showstu() {
for k, v := range allstu {
fmt.Printf("学号:%d,姓名:%s\n", k, v.name)
}
}
func addstu() {
var (
id int64
name string
)
fmt.Println("请输入学生的学号")
fmt.Scanln(&id)
fmt.Println("请输入学生的姓名")
fmt.Scanln(&name)
stu := newstu(id, name)
allstu[id] = stu
}
func delstu() {
fmt.Println("请输入要删除的学号:")
var sid int64
fmt.Scanln(&sid)
delete(allstu, sid)
fmt.Println("删除成功")
}