golang--day5结构体+结构体排序+错误处理+结构体和接口实现面向对象的例子
2023-02-19 10:46 dribs 阅读(33) 评论(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)
}
浙公网安备 33010602011771号