2022-5-13 实习Day35 1、行内汇款——申报交易完成在监管报送平台查询不到问题排查。 –3小时 20% 2、汇入汇款不申报,有境外申报单问题排查 –2小时 80% 3、代理行业务测试 –2小时 30%
Golang编程学习(part 30) 1、面向对象编程思想—抽象的介绍 我们在前面去定义一个结构体的时候,实际上就是把一类事物的共有属性(字段)和行为(方法)提取出来,形成一个物理模型(结构体),这种研究问题的方法称为抽象 2、面向对象编程三大特性—封装 封装(encapsulation)就是把抽象出的字段和对字段的操作封装在一起,数据被保护在内部,程序的其他包只有通过被授权的操作(方法),才能对字段进行操作【封装的好处:1)隐藏实现细节。2)可以对数据进行验证,保证安全合理】 ① 封装的实现步骤 1)将结构体、字段(属性)的首字母小写【不能导出了,其他包不能使用,类似private】
2)给结构体所在包提供一个工厂模式的函数,首字母大写,类似一个构造函数
3)提供一个首字母大写的Set方法(类似其他语言的public),用于对属性判断并赋值
1 2 3 4 func (var 结构体类名) SetXxx(参数列表) (返回值列表) { var .字段 = 参数 }
4)提供一个首字母大写的Get方法(类似其他语言的public),用于获取属性的值
1 2 3 func (var 结构体类名) GetXxx(){ return var .age }
特别说明:在Golang中没有特别强调封装,这点并不像java,所以提醒学过java的同学,不用总是用java的语法特性来看待Golang,Golang本身对面向对象的特性做了简化的。 ② 快速入门案例 1 2 // 请大家看一个程序(person.go),不能随便查看人的年龄、工资等隐私,并对输入的年龄进行合理的 // 验证。设计:model包(person.go) main包(main.go调用Person结构体)
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 package modelimport ("fmt" )type person struct { age int salary float64 } func NewPerson (age int , salary float64 ) (*person){ return &person{age, salary} } func (p *person) SetSalary(salary float64 ) { (*p).salary = salary } func (p *person) GetSalary() (float64 ){ return (*p).salary } func (p *person) SetAge(age int ) { if age > 0 && age < 150 { (*p).age = age } else { fmt.Println("年龄范围不正确" ) } } func (p *person) GetAge() (int ){ return (*p).age }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package mainimport ( "Test1/model" "fmt" ) func main () { person := model.NewPerson(25 , 300000 ) fmt.Println(*person) person.SetAge(30 ) person.SetSalary(100 ) fmt.Println(person.GetAge(), person.GetSalary()) fmt.Println(*person) } {25 300000 } 30 100 {30 100 }
3、面向对象编程三大特性—继承 为什么需要继承?比如小学生和大学生,他们都有一些相同的字段和方法。所以这也就造成了我们会写一些相同的代码,代码的重复利用性不强。其次,代码也比较冗余,而且不利于维护,同时也不利于功能的扩展。因此我们要通过继承的方式来解决该问题 继承可以解决代码复用,让我们的编程更加靠近人类思维。当多个结构体存在相同的属性(字段)和方法时,可以从这些结构体中抽象出结构体(比如刚才的Student),在该结构体中定义这些相同的属性和方法。 其他的结构体不需要重新定义这些属性(字段)和方法,只需嵌套一个Student匿名结构体即可。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |------------------| | Student | | 共有的字段 | | 共有的方法 | |------------------| /|\ /|\ | | | | | | |----------------| |------------------| | Pupil | | Graduate | | 特有字段 | | 特有字段 | | 特有方法 | | 特有方法 | |匿名结构体Student| | 匿名结构体Student| | (实现继承特性) | | (实现继承特性) | |----------------| |-----------------| 也就是说:在Golang中,如果一个struct嵌套了另一个匿名结构体,那么这个结构体可以直接访问匿名 结构体的字段和方法,从而实现了继承特性
① 嵌套匿名结构体的基本语法 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 package mainimport "fmt" type Goods struct { Name string Price int } type Book struct { Goods Writer string } func main () { b := new (Book) (*b).Writer = "尼克" (*b).Price = 26 (*b).Name = "活着" fmt.Println(*b) } {{活着 26 } 尼克}
② 继承的深入讨论 1)结构体可以使用嵌套匿名结构体所有的字段和方法,即:首字母大写或小写的字段、方法,都可以使用。【跨包会有问题】
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 package mainimport ( "fmt" ) type Student struct { Name string age int } func (s *Student) SayOk() { fmt.Println("A SayOk" , (*s).Name) } func (s *Student) hello() { fmt.Println("hello" , (*s).Name) } type Graduate struct { Student } func main () { g := new (Graduate) (*g).Student.Name = "tom" (*g).Student.age = 25 (*g).Student.SayOk() (*g).Student.hello() } A SayOk tom hello tom
2)匿名结构体字段访问可以简化
1 2 3 4 (*g).Name = "tom" (*g).age = 25 (*g).SayOk() (*g).hello()
对上面代码小结: 【1】当我们直接通过g访问字段或者方法时,其执行流程如下,比如(*g).Name 【2】编译器会先看g对应的类型有没有Name,如果有,则直接调用Gradute类型的Name字段 【3】如果没有就去看B中嵌入的匿名结构体Student有没有声明Name字段,如果有就调用,如果没有就继续查找,如果都找不到就报错 3)当结构体和匿名结构体有相同的字段或者方法时,编译器采用就近访问原则访问,如希望访问匿名结构体的字段和方法,可以通过匿名结构体名来区分
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 package mainimport "fmt" type Student struct { Name string age int } type Graduate struct { Student Name string } func (s *Student) hello() { fmt.Println("hello" , (*s).Name) } func (s *Graduate) hello() { fmt.Println("hello" , (*s).Name) } func main () { var g Graduate g.Name = "gra" fmt.Println(g) g.Student.Name = "jackstudent" fmt.Println(g) g.hello() g.Student.hello() }
4)结构体嵌入两个(或多个)匿名结构体,如两个匿名结构体有相同的字段和方法(同时结构体本身没有同名的字段和方法),在访问时就必须明确指定匿名结构体名字,否则编译报错。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package mainimport "fmt" type A struct { Name string age int } type B struct { Name string Score float64 } type C struct { A B } func main () { var c C c.A.Name = "jack" c.B.Name = "lisa" fmt.Println(c) }
5)如果一个struct嵌套了一个有名结构体,这种模式就是组合,如果是组合关系,那么在访问组合的结构体的字段或方法时,必须带上结构体的名字
1 2 3 4 5 6 7 type D struct { a A } var d Dd.a.Name = "jack"
6)嵌套匿名结构体后,也可以在创建结构体变量(实例)时,直接指定各个匿名结构体字段的值
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 package mainimport "fmt" type Goods struct { Name string Price float64 } type Brand struct { Name string Address string } type TV struct { Goods Brand } type TV2 struct { *Goods *Brand } func main () { tv := TV{ Goods{"电脑" , 5000 }, Brand{"夏普" , "中国" }, } fmt.Println(tv) tv2 := TV2{ &Goods{ "电视" , 6000 , }, &Brand{ "小米" , "中国" , }, } fmt.Println(*tv2.Brand, *tv2.Goods) } {{电脑 5000 } {夏普 中国}} {小米 中国} {电视 6000 }
7)结构体的匿名字段是基本数据类型,如何访问?
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 package mainimport "fmt" type Monster struct { Name string Age int } type Boss struct { Monster int n int } func main () { var b Boss b.Name = "树妖" b.Age = 300 b.int = 2 b.n = 50 fmt.Println(b) } {{树妖 300 } 2 50 }
如果一个结构体有int类型的匿名字段,就不能有第二个 如果需要多个int的字段,则必须给int字段指定名字