代码改变世界

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)

}