golang--day5结构体+结构体排序+错误处理+结构体和接口实现面向对象的例子
2023-02-19 10:46 dribs 阅读(20) 评论(0) 编辑 收藏 举报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排序
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) }
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.计算完的面积排序处理
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) }