代码改变世界

golang--day5结构体+结构体排序+错误处理+结构体和接口实现面向对象的例子

  dribs  阅读(25)  评论(0编辑  收藏  举报
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package main
 
import (
    "fmt"
)
 
//初始化
type User struct {
    id         int
    name, addr string
    float32    //匿名成员变量 必须类型不一样才能区分
}
type Point struct {
    x, y int
}
 
//成员方法
//u 称为receiver
//等价于func (User)string
func (u User) getName() string {
    return u.name
}
func (p *Point) setY(v int) {
    fmt.Printf("p9set:%+v,%p\n", p, p)
    p.y = v
}
func (p Point) getY() int {
    return p.y
}
 
//构造函数 go本身没有为结构体提供构造器
//但是有时候可以通过一个函数为结构体初始化提供属性值
//从而方便得到一个结构体实例,习惯以Newxxx的形式命名
type Animal struct {
    name string
    age  int
}
 
func NewAnimal(name string, age int) *Animal {
    //a := Animal{name, age}
    //fmt.Printf("%+v,%p\n", a, &a)
    //return &a
    return &Animal{name, age} //习惯上返回值采用指针类型避免实例的拷贝
}
 
func main() {
    //1 var声明 非常常用
    var u1 User //这种方式声明结构体变量很方便,所有字段都是零值
    fmt.Println(u1)
    fmt.Printf("%+v\n", u1) //加上字段打印
    fmt.Printf("%#v\n", u1) //打印更多信息
    //2 字面初始化 推荐
    u2 := User{} //字段为零值
    fmt.Printf("u2:%#v\n", u2)
    //3 字面量初始化 field:value 为字段赋值
    u3 := User{id: 100}
    fmt.Printf("u3:%+v\n", u3)
    //访问
    fmt.Println(u3.id)
    //修改
    u3.id = 200
    u3.name = "Tom"
    fmt.Println(u3)
    //通过成员方法访问
    fmt.Println(u3.getName())
 
    //指针
    var p1 = Point{10, 20} //实例
    fmt.Printf("p1:%T,%[1]v\n", p1)
    var p2 = &Point{5, 6} //指针
    fmt.Printf("p2:%T,%[1]v\n", p2)
    var p3 = new(Point) //new实例化一个结构体并返回
    fmt.Printf("p3:%T,%[1]v\n", p3)
    //通过实例修改属性
    p1.x = 100
    fmt.Printf("%T,%[1]v\n", p1)
 
    p4 := p1 //多了一个副本,内存地址不一样
    fmt.Printf("p1:%+v %p\n", p1, &p1)
    fmt.Printf("p4:%+v %p\n", p4, &p4)
    p5 := &p1 //p5 就是p1的引用了 传递的是一个地址
    fmt.Printf("p5:%+v %p\n", p5, p5)
    var p6 = func(p Point) Point {
        fmt.Printf("p6inner:%+v,%p\n", p, &p)
        return p
    }(p1)
    fmt.Printf("p6outer:%+v,%p\n", p6, &p6)
    //可以看出 结构体是非引用类型 使用的是值拷贝,传参活返回值如果使用结构体实例,将产生很多副本
    //如何避免多副本,保证函数内外是同一个结构体实例,使用指针
    var p7 = func(p *Point) *Point {
        p.x += 200
        fmt.Printf("p7inner:%+v,%p\n", p, p)
        return p
    }(p5)
    p7.x += 1
    fmt.Printf("p1:%+v %p\n", p1, &p1)
    fmt.Printf("p7outer: %+v,%p\n", p7, &p7)
    p8 := p5
    p8.y = 400 //会发生什么??
    fmt.Printf("p1:%+v %p\n", p1, &p1)
    fmt.Printf("p8: %+v,%p\n", p8, p8)
 
    //匿名结构体,标识符直接使用struct部分结构体本身作为类型,而不是使用type定义的有名字的结构体的标识符
    //可以使用 var const := 来定义匿名结构体,结构体可以反复定义其实例,但匿名的是一次性的
    var point struct {
        x, y int
    }
    fmt.Printf("匿名结构体:%v\n", point) //得到的是一个结构体的实例,默认是零值
    var message = struct {
        id   int
        data string
    }{1, "abc"} //不用零值初始化 注意有个=
    fmt.Printf("%v\n", message)
    //匿名成员
    var u4 = User{id: 10, name: "Bob", float32: 1.111} //使用类型名float最为字段名
    fmt.Println(u4, u4.float32)
 
    //构造函数
    a := NewAnimal("Tom", 18)
    fmt.Printf("构造函数:%+v,%p\n", a, a) //返回的指针和构造函数里一样
 
    //指针类型recevier
    p9 := Point{66, 88}
    fmt.Printf("p9:%+v,%p\n", p9, &p9)
    p9.setY(201) //看似是Point{66, 88}实例调用,因为func (p *Point) setY 所以实际是指针,操作同一处地址
    fmt.Println(p9.getY())
}

 

对切片排序和利用结构体对map排序  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package main
 
import (
    "fmt"
    "sort"
)
 
type Student struct {
    Name string
    Age  int
}
 
//用于对map的value排序使用,map的格式很像struct格式
type Entry struct {
    key   int
    value string
}
 
type StudentSlice []Student
 
func (x StudentSlice) Len() int {
    return len(x)
}
func (x StudentSlice) Swap(i, j int) {
    x[i], x[j] = x[j], x[i]
}
func (x StudentSlice) Less(i, j int) bool {
    return x[i].Age > x[j].Age
}
func main() {
    students := make([]Student, 0, 3)
    students = append(students, Student{"Tom", 19})
    students = append(students, Student{"Jack", 18})
    students = append(students, Student{"Rose", 20})
    fmt.Println(students)
    sort.Sort(StudentSlice(students))
    fmt.Println(students)
 
    //简化版13-23行的代码可以去掉,直接匿名函数实现Less
    sort.Slice(students, func(i, j int) bool {
        return students[i].Age < students[i].Age
    })
    fmt.Println(students)
 
    //对map排序之对map的key排序,先取出key,放到int[]切片里,然后对int[]切片排序,在根据排序好的切片 获取map对应的value
    m := make(map[int]string)
    m[1] = "b"
    m[2] = "c"
    m[0] = "a"
    var keys []int
    for k := range m {
        keys = append(keys, k)
    }
    sort.Ints(keys)
    for _, v := range keys {
        fmt.Println(v, m[v])
    }
 
    //对map排序之对map的value排序
    //创建一个Entry类型的切片,存放字典里的k,v
    p := make([]Entry, len(m))
    i := 0
    //
    for k, v := range m {
        p[i] = Entry{k, v}
        i++
    }
    fmt.Println(p)
    sort.Slice(p, func(i, j int) bool {
        return p[i].value > p[j].value
    })
    fmt.Println(p)
}

  

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package main
 
import (
    "errors"
    "fmt"
    "io/fs"
    "os"
)
 
//panic执行:
//逆序执行当前已经注册过的goroutine的defer链(recover从这里介入)
//打印错误信息和调用堆栈
//调用exit(2)结束整个进程
//recover 类似python的 try catch 捕获异常
 
var ErrdivisionByZero = errors.New("division by zero") //构造一个错误实例
 
func div(a, b int) int {
    defer func() {
        err := recover() //一旦recover了,就相当处理过了错误
        println(1, err, "====")
    }()
    defer fmt.Println("start")
    defer fmt.Println(a, b)
    defer func() {
        println("错误捕获")
        err := recover()
        switch err.(type) { //类型断言
        case *fs.PathError:
            println("文件不存在", err)
        case []int:
            println("切片", err)
        }
        println("离开")
    }()
    if f, err := os.Open("o:/tttt.txt"); err != nil {
        panic(err)
    } else {
        println(f)
    }
    r := a / b
    println("end")
    return r
}
 
func main() {
    println(div(5, 0))
}

  

1.计算三角形长方形圆形的面积

2.计算完的面积排序处理

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package main
 
import (
    "fmt"
    "sort"
)
 
//定义Area接口 用于多态实现
type Areaer interface {
    area() int
}
 
//圆形
type Yuan struct {
    pi float32
    r  int
}
 
//长方形
type Chang struct {
    w, l int
}
 
//三角形
type San struct {
    Chang //匿名嵌套长方形,实现继承的效果
}
 
//第二题构建三个以上图形排序的结构体
type AllGraph struct {
    name string
    area int
}
 
//第二题使用,构造函数
func NewAllGraph(name string, area int) *AllGraph {
    return &AllGraph{name, area}
}
 
//第二题使用排序
type AllgraphSlice []AllGraph
 
func (x AllgraphSlice) Len() int      { return len(x) }
func (x AllgraphSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x AllgraphSlice) Less(i, j int) bool {
    //降序排序
    return x[i].area > x[j].area
 
}
 
//实现多态
func foo(a Areaer) int {
    //a.area()
    return a.area()
}
 
//求三种类型的面积*(圆 长方形 三角形)
func (y *Yuan) area() int {
    area := y.pi * float32(y.r*y.r)
    //fmt.Printf("圆形面积是:%.f\n", area)
    return int(area)
}
func (c *Chang) area() int {
    area := c.w * c.l
    //fmt.Printf("长方形面积是:%d\n", area)
    return area
}
func (s *San) area() int {
    area := s.w * s.l / 2
    //fmt.Printf("三角形面积是:%d\n", area)
    return area
}
 
func main() {
    //第一题求面积
    //圆形面积 pi*r^2
    y1 := &Yuan{3.14, 3}
    //y1.area()
    fmt.Printf("圆形面积是:%d\n", y1.area())
 
    //长方形面积 长*宽
    c1 := new(Chang)
    c1.w = 3
    c1.l = 4
    //c1.area()
    fmt.Printf("长方形面积是:%d\n", c1.area())
 
    //三角形面积 底*高/2 ,三角形继承长方形,多态实现求面积
    s1 := &San{}
    s1.w = 10
    s1.Chang.l = 4
    //foo(s1)
    fmt.Printf("三角形面积是:%d\n", foo(s1))
 
    //+++++++++++++++++++++++++++++++++++++++++++++++++
    //第二题对面积排序 使用切片方式排序
    //构建三个实例,构建成map也适用
    n1 := NewAllGraph("Yuan", foo(y1))
    n2 := NewAllGraph("Chang", foo(c1))
    n3 := NewAllGraph("San", foo(s1))
    alls := []AllGraph{*n1, *n2, *n3}
    fmt.Println("排序前:", alls)
    //对结构体 降序排序
    sort.Sort(AllgraphSlice(alls))
    fmt.Println("排序后:", alls)
    //切片排序第二种方法 简易版
    sort.Slice(alls, func(i, j int) bool {
        //升序
        return alls[i].area < alls[j].area
    })
    fmt.Println("升排序:", alls)
 
    //对key string类型排序
    var keys []string
    for i := 0; i < len(alls); i++ {
        keys = append(keys, alls[i].name)
    }
    //区分验证上面的排序准确性 在单独append追加一个string,没写完还要一个map 不想写了
    keys = append(keys, "AAA")
    sort.Strings(keys)
    fmt.Println(keys)
 
}

  

相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示