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)
}
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)
}
也就是都要在结构体完全相同的情况下可以进行强转
上面的结构体绑定方法是用的值传递
用视频中的例子来解释
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)
}
在方法中去更改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)
}
package main
type integer int
func (i integer) print() {
print("wuwuwuwu")
}
func main() {
var i integer = 1
i.print()
}
是和函数一样的,如果首字母小写,只能在本包进行访问, 如果首字母大写了,就可以在其他包中进行访问.
如果一个类型实现了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)
}
类似Java中的toString方法
在定义结构体的时候,可以把这个方法定义好,常用来作为输出结构体信息的方法
这里的结构体名首字母大写,字段名首字母也要大写,否则没法被外部包访问.
上面我们知道,要外部包访问结构体,结构体名首字母必须大写,但是如果小写了,我还是想访问,怎么办?
这里就出现了工厂模式
可是无论怎么样,在结构体中,字段名的首字母都要大写.
通过调用函数来返回结构体指针.
封装就是把抽象的字段和对字段的操作封装到一起,数据被保护在内部,程序的其他包通过授权的操作方法,才能对字段进行操作.
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语言弱化了,但是写代码过程中思维要清楚
上面就是匿名结构体实现继承的图解释.
代码展示一下:
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()
}
第五个如果不做区分是会报错的
这个组合类型不是继承关系
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中,多态是通过接口来实现的.
可以按照统一的接口来调用不同的实现. 这时接口变量就呈现不同的形态.
就是上面接口中的不同国家的人的打招呼
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语言里面有一个语法,可以直接判断是否是该类型的变量:value , ok = element.(T), 这里的value就是变量的值, ok是一个bool类型, element是interface变量, T是断言的类型