学习笔记 golang
面向对象基础
- struct基础:自定义类型,Go支持只提供类型,而不写字段名的方式,也就是匿名字段,也称为嵌入字段。当匿名字段是一个struct的时候,那么这个struct所拥有的全部字段都被隐式地引入了当前定义的这个struct。
// 定义一个 人类 struct
type person struct {
name string
age int
}
// 定义一个 学生 struct,继承了人类struct
type student struct {
person // 匿名字段
class1 int
tercherName string
}
func s1() {
var p1 person
p1.age = 22
p1.name = "John"
fmt.Println(p1)
p2 := person{name:"Jack", age:55}
fmt.Println(p2)
}
func s2() {
var student = student{person{"小红", 18}, 8, "陈老师"}
fmt.Println(student)
student.tercherName = "老李"
fmt.Println(student.name, student.person.name)
}
func main() {
s1()
s2()
}
- 属于struct的方法(类内的方法)
假如要计算面积,一般思路如下方法一所示:但是areaRectangle()不是作为Rectangle的方法实现的(类似面向对象里面的方法),而是将Rectangle的对象(如r1,r2)作为参数传入函数计算面积的,那么如果增加一个图形,想计算面积就只能增加新的函数,函数名也必须要跟着更换,变成area_rectangle, area_circle, area_triangle...
。用面向对象的思想来说,面积应该是对象的一个方法Rectangle.area()
,而非外围函数。
type Rectangle struct {
width, height float64
}
type Cricle struct {
radius float64
}
func areaRectangle(r Rectangle) float64 {
return r.height * r.width
}
//func areaCricle(c Cricle) float64 {
// // 计算公式等等...
//}
func main() {
// 计算长方形面积方法一
// 如果有多个不同的形状如圆形,就需再写一个外部方法来计算,由此引出方法二:写一个从属struct的方法
var rec1 = Rectangle{4, 9}
res1 := areaTest(rec1)
fmt.Println(res1)
}
定义method语法:func (r ReceiverType) funcName(parameters) (results)
,则如上例子可以用下面method来实现
type Rectangle struct {
width, height float64
}
type Cricle struct {
radius float64
}
func (r Rectangle) area() float64 {
return r.width * r.height
}
func (c Cricle) area() float64 {
return c.radius * c.radius * math.Pi
}
func main() {
var rectangle = Rectangle{3, 5}
var cricle = Cricle{10}
fmt.Println(rectangle.area())
fmt.Println(cricle.area())
}
注意 :虽然method的名字一模一样,但是主体不一样,那么method就不一样;method里面可以访问接收者的字段;默认情况下方法的Receiver(即类主体)是值传递,而非引用,在method里改变字段是不影响原类的,method同样支持传递引用;调用method通过.访问,就像struct里面访问字段一样。
代码语言:javascript复制func (r *Rectangle) area2() float64 {
r.width = 10 // 问题:这里为什么没用 *r.width = 10 ?
return r.width * r.height
}
// 先调用area2,发现rectangle已经被更改了,因为传递了引用
fmt.Println(rectangle.area2())
fmt.Println(rectangle)
问题解答: 如果一个method的receiver是T,你可以在一个T类型的实例变量V上面调用这个method,而不需要&V去调用这个method;如果一个method的receiver是T,你可以在一个T类型的变量P上面调用这个method,而不需要 *P去调用这个method;所以不用担心你是调用的指针的method还是不是指针的method,Go已经帮你搞定了。
method继承:如果匿名字段实现了一个method,那么包含这个匿名字段的struct也能调用该method
代码语言:javascript复制type Rectangle struct {
width, height float64
}
type someStruct struct {
Rectangle // 继承rectangle,则可以调用所有方法
params int
}
s1 := someStruct{Rectangle{5, 8}, 10}
fmt.Println(s1.area()) // 40
fmt.Println(s1) // {{5 8} 10}
method 重写:
代码语言:javascript复制type Rectangle struct {
width, height float64
}
type someType struct {
Rectangle
deep float64
}
func (r Rectangle) area(x float64) (res float64) {
// 在函数定义了返回值就不需要在函数内重重新声明,直接return即可
// var res float64
if x > 0 {
res = r.width * r.height * x
} else {
res = r.width * r.height
}
return
}
// 重写area方法
func (s someType) area(x float64) (res float64) {
if x > 0 {
res = s.width s.height x
} else {
res = s.width s.height
}
return
}
var someType = someType{Rectangle{2, 5}, 3}
fmt.Println(someType) // {{2 5} 3}
fmt.Println(someType.Rectangle.area(1)) // 10
fmt.Println(someType.area(1)) // 8
interface
interface可以理解为是一组method签名的组合,我们通过interface来定义对象的一组行为。
代码语言:javascript复制// 学生接口 interface就是一组抽象方法的集合
type studentInterface interface {
sayHi()
sing()
//changeSchool(schoolName string)
}
// Human 结构体
type Human struct {
name string
age int
phone string
}
// Student结构体,继承Human
type Student struct {
Human
school string
grade int
}
// Human 对象实现Sayhi方法
func (human Human) sayHi() {
fmt.Printf("hi, i am %s, and i am %d, call me %s", human.name, human.age, human.phone)
}
// Human 对象实现Sing方法
func (human Human) sing() {
fmt.Println("lalalalala")
}
// Human 对象实现Guzzle方法
func (human Human) Guzzle(beerStein string) {
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}
// student 重载Human的sayHi方法
func (student Student) sayHi() {
fmt.Println("hi im a student, my name is", student.name, "grade is", student.grade)
}
// student 重载Human的sing方法
//func (student Student) sing() {
// fmt.Println("lala")
//}
// student 实现转学方法
func (student *Student) changeSchool(schoolName string) {
student.school = schoolName
}
// 执行方法
func interfaceTest() {
var studentI studentInterface
var Tom = Student{Human{"tom", 18, "13000000000"},"北京大学", 8}
var John = Human{"shyzhen", 26, "14526555544"}
// 对象必须完全实现了interface定义的方法才能赋值 可多不可少。如Student同时实现了changeSchool方法,接口中并未定义。
studentI = Tom
studentI.sayHi()
studentI.sing()
studentI = John
studentI.sayHi()
studentI.sing()
Tom.sayHi()
Tom.sing()
Tom.changeSchool("清华大学")
fmt.Println(Tom)
John.sayHi()
John.sing()
}
由于所有的类型都实现了空interface,一个函数把interface{}作为参数,那么他可以接受任意类型的值作为参数,如果一个函数返回interface{},那么也就可以返回任意类型的值。
代码语言:javascript复制func interfaceTest2(params interface{}) interface{} {
return params
}
fmt.Println(interfaceTest2("sssss"))
fmt.Println(interfaceTest2(2323))