> 文章列表 > Go面向对象

Go面向对象

Go面向对象

前言

Go面向对象

Go也有面向对象

面向对象引入:

Go面向对象

用面向对象好啊

结构体定义

GO中的结构体和其他语言中的class是同一个等级的
Go面向对象

这个就懒得写了 , 直接贴一个

内存分析

Go面向对象

当实例化一个结构体的时候,分配一份内存空间.

结构体实例的创建

package main  import "fmt"  type Teacher struct {  Name   string  age    int  School string  
}  func main() {  // 实例化方法一:  var t1 Teacher // var a int  fmt.Println(t1)  // 实例化方法二:  var t2 Teacher = Teacher{  Name:   "simple",  age:    0,  School: "ssss",  }  // 实例化方法三:  var t3 Teacher = Teacher{}  t3.age = 10  //实例化方法四:  //t4是一个指针,t4其实指向的就是地址, 应该给这个地址的指向的对象的字段赋值.  var t4 *Teacher = new(Teacher)  (*t4).Name = "simple"  (*t4).age = 24  // 为了符合程序员的编程习惯,go提供了简单的赋值方式  t4.Name = "sim"  t4.age = 25  // 实例化方式五:  var t5 *Teacher = &Teacher{}  (*t5).Name = "simple"  (*t5).age = 11  t5.School = "ajglajgl"  
}

五种方式的实例化

结构体之间的转换:

  • 结构体是用户自定义的类型, 和其他类型进行转换时需要有完全相同字段(名字,个数, 类型)
package main  import "fmt"  type Student struct {  age int  
}  type Person struct {  age int  
}  func main() {  var s Student = Student{age: 10}  var p Person = Person{age: 10}  s = Student(p)  fmt.Println(s)  fmt.Println(p)  }
  • 结构体进行type重新定义(相当于重新取别名),Go认为是新的数据类型,但是相互间可以强转
package main  import "fmt"  type Student struct {  age int  
}  type Stu Student  func main() {  var s1 Student  var s2 Stu  s1 = Student(s2)  fmt.Println(s1)  fmt.Println(s2)  }

也就是都要在结构体完全相同的情况下可以进行强转

方法:

Go面向对象

上面的结构体绑定方法是用的值传递
用视频中的例子来解释

package main  type Boy struct {  Name string  
}  func (b Boy) tets() {  b.Name = "complex"  println("方法")  println(b.Name)  
}  func main() {  var boy Boy  boy.Name = "simple";  boy.tets()  println(boy.Name)  }

Go面向对象

在方法中去更改Name的值,只是更改了传给方法的结构体的副本的值, 但是原本的结构体并没有被更改.

结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式.

如果程序员希望在方法中,改变了结构体中字段的值, 原来的结构体中的值也被改变,就需要用引用传递的方式来绑定变量了

其实上面的也就是值方法和指针方法的区别
https://zhuanlan.zhihu.com/p/101363361
下面就将上面的值方法改陈指针方法:

package main  type Boy struct {  Name string  
}  func (b *Boy) tets() {  b.Name = "complex"  println("方法")  println(b.Name)  
}  func main() {  var boy Boy  boy.Name = "simple"  boy.tets()  println(boy.Name)  }

Go面向对象

指定数据类型的方法

package main  type integer int  func (i integer) print() {  print("wuwuwuwu")  
}  func main() {  var i integer = 1  i.print()  }

方法的访问控制规则

是和函数一样的,如果首字母小写,只能在本包进行访问, 如果首字母大写了,就可以在其他包中进行访问.

方法的trick

如果一个类型实现了String()这个方法, 那么fmt.Println默认会调用这个变量的String()进行输出.

package main  import "fmt"  type Animal struct {  name string  age  int  
}  func (a *Animal) String() string {  str := fmt.Sprintf("name = %v , age = %v", a.name, a.age)  return str  
}  
func main() {  animal := Animal{  name: "cat",  age:  11,  }  //传入地址,如果绑定了String方法就会自动调用了  fmt.Println(&animal)  
}

Go面向对象

类似Java中的toString方法
在定义结构体的时候,可以把这个方法定义好,常用来作为输出结构体信息的方法

跨包创建结构体示例

Go面向对象

这里的结构体名首字母大写,字段名首字母也要大写,否则没法被外部包访问.
Go面向对象

工厂模式

上面我们知道,要外部包访问结构体,结构体名首字母必须大写,但是如果小写了,我还是想访问,怎么办?
这里就出现了工厂模式
Go面向对象

Go面向对象

可是无论怎么样,在结构体中,字段名的首字母都要大写.
通过调用函数来返回结构体指针.

封装的引入

什么是封装:

封装就是把抽象的字段和对字段的操作封装到一起,数据被保护在内部,程序的其他包通过授权的操作方法,才能对字段进行操作.

封装的好处:

  • 隐藏实现细节
  • 提高对数据的验证,保证安全性

如何实现:

  • 建议将结构体,字段的首字母小写(其他包就不能使用了,类似于private)
  • 给结构体所在的包提供一个工厂模式的函数,首字母小写(类似一个构造函数)
  • 提供一个首字母大写的Set方法(类似其他语言的public),用于对属性的判断和赋值
  • 提供一个首字母大写的Get方法(类似其他语言的public),用于获取属性的值
    Go的封装不是很严格
package student  type person struct {  Name string  age  int //其他包不能访问  
}  // 定义工厂模式的函数,相当于构造器  
func NewPerson(name string) *person {  return &person{  Name: name,  }  
}  // 定义Set和Get方法对字段进行封装,  
func (p *person) SetAge(age int) {  if age > 0 && age < 120 {  p.age = age  } else {  print("输入不合法")  }  }  func (p *person) GetAge() int {  return p.age  
}

这里的person中的两个字段,一个是首字母大写的, 一个是全小写的,Name就可以用工厂模式来弄,而age就只能通过方法来弄了

Go面向对象

继承:

多个结构体存在相同属性,可以吧这些结构体中抽象出一个结构体,该结构体中定义这些相同的字段,其他结构体就可以不用重复写这些字段了.
在GO中,其他结构体不用重新定义这些属性和方法了,只需要嵌套一个匿名结构体就行.
Go面向对象

这些继承,父类,子类被Go语言弱化了,但是写代码过程中思维要清楚
Go面向对象

上面就是匿名结构体实现继承的图解释.

代码展示一下:

package main  import "fmt"  type Animal struct {  Age    int  Weight float32  
}  // Animal的方法:  
func (a *Animal) Shout() {  fmt.Println("叫")  
}  func (a *Animal) ShowInfo() {  fmt.Println(a.Age, a.Weight)  
}  //定义猫的结构体  
type Cat struct {  // 继承:用匿名结构体来做  Animal  
}  //Cat 的方法  func (c *Cat) Scratch() {  fmt.Println("猫的爪子")  
}  func main() {  cat := &Cat{Animal{  Age:    10,  Weight: 10,  }}  cat.Animal.Age = 11  cat.Animal.Weight = 11  cat.Animal.Shout()  cat.Animal.ShowInfo()  cat.Scratch()  }

Go面向对象

注意事项:
Go面向对象

其实都是比较好理解的,就不做code了
Go面向对象

第五个如果不做区分是会报错的

第六个
Go面向对象

组合类型
Go面向对象

这个组合类型不是继承关系

接口:

package main  import (  "fmt"  
)  //定义一个接口:接口一些规则,规范,某种能力  
//这里是抽象理解一个说你好的能力  
type Sayhello interface {  //声明一个没有实现的方法  Sayhello()  
}  //接口的实现:定义一个结构体  
//中国人:  
type Chinese struct {  
}  //实现接口的方法  
func (c *Chinese) Sayhello() {  fmt.Println("你好")  
}  type English struct {  
}  func (e *English) Sayhello() {  println("hi")  
}  func main() {  chinese := &Chinese{}  chinese.Sayhello()  english := English{}  english.Sayhello()  
}
你好
hi

所以就是如果一个结构体实现了接口中的所有定义的方法,这个结构体就实现了这个接口.

看看这个接口可做什么?

package main  import (  "fmt"  
)  // 定义一个接口:接口一些规则,规范,某种能力  
// 这里是抽象理解一个说你好的能力  
type Sayhello interface {  //声明一个没有实现的方法  Sayhello()  
}  // 接口的实现:定义一个结构体  
// 中国人:  
type Chinese struct {  
}  // 实现接口的方法  
func (c *Chinese) Sayhello() {  fmt.Println("你好")  
}  type English struct {  
}  func (e *English) Sayhello() {  println("hi")  
}  // 定义一个函数:用来专门向各个国家的人打招呼的函数,接收具备Sayhello接口的能力的变量  
func greet(s Sayhello) {  s.Sayhello()  
}  func main() {  chinese := &Chinese{}  chinese.Sayhello()  english := &English{}  english.Sayhello()  greet(chinese)  greet(english)  }

Go面向对象

接口是一个隐式的实现.
要求并不严格
接口的目的是为了让定义规范
其实也和下面的多态有关系

多态

基本介绍:

变量(实例)具有多种形态.面向对象的第三大特征, 在Go中,多态是通过接口来实现的.
可以按照统一的接口来调用不同的实现. 这时接口变量就呈现不同的形态.

案例

就是上面接口中的不同国家的人的打招呼

package main  import (  "fmt"  
)  // 定义一个接口:接口一些规则,规范,某种能力  
// 这里是抽象理解一个说你好的能力  
type Sayhello interface {  //声明一个没有实现的方法  Sayhello()  
}  // 接口的实现:定义一个结构体  
// 中国人:  
type Chinese struct {  
}  // 实现接口的方法  
func (c *Chinese) Sayhello() {  fmt.Println("你好")  
}  type English struct {  
}  func (e *English) Sayhello() {  println("hi")  
}  // 定义一个函数:用来专门向各个国家的人打招呼的函数,接收具备Sayhello接口的能力的变量  
func greet(s Sayhello) {  s.Sayhello()  
}  func main() {  chinese := &Chinese{}  english := &English{}  greet(chinese)  greet(english)  }

接口体现多态特征

  • 多态参数:
    Go面向对象

  • 多态数组
    Go面向对象

断言

什么是断言:

Go语言里面有一个语法,可以直接判断是否是该类型的变量:value , ok = element.(T), 这里的value就是变量的值, ok是一个bool类型, element是interface变量, T是断言的类型