目录
go语言中不仅有函数还有方法。其实他们之间的区别并不是很大,函数只要声明定义了以后只要在它的作用域类就可以使用函数,而方法就是多了一个接收者,我们只有通过接收者来调用这个方法,感觉能够更加体现出封装的感觉。这个接收者可以是值对象接收者也可以是指针对象接收者,但是接收者不能够是内置数据类型。
语法格式如下:
func (variable_name variable_data_type) function_name( 参数列表) [return_type] {
/* 函数体*/
}
1 方法的定义和使用
值对象接收者
func (p People) GetName() string {
return p.Name
}
- 无须修改状态的小对象或者固定值
- 引用类型、字符串或者函数等
- 调用时会按照其一个副本来执行调用 (所以当我们有需求对接收者的内容进行变更的时候就不能够使用值对象作为接收者了)
指针对象接收者
func (p *People) GetAge() uint {
return p.Age
}
- 修改实例状态
- 大对象
- 调用时会按照实际值来执行调用
代码实例:
package main
import "fmt"
type Student struct {
id int
name string
}
// 无参数列表与返回值
func (stu Student) method1() {
}
// 有参数列表无返回值
func (stu Student) method2(id int, name string) {
}
// 有参数列表有返回值
func (stu Student) method3(id int, name string) int {
return 0
}
// 有参数列表并且多个返回值
func (stu Student) method4(id int, name string) (a, b int) {
return 0, 0
}
// 只要是值对象接受者 就不能够对其内容进行修改 因为操作的是一个备份
func (stu Student) method5(id int, name string) *Student {
stu.id = id
stu.name = name
return &stu
}
// 指针对象接受者 我们可以对内容进行修改了
func (stu *Student) method6(id int, name string) *Student {
stu.id = id
stu.name = name
return stu
}
//虽然接收者是一个值对象 但是传入值和指针对象都能够成功的调用这个方法
func (stu Student) showMessage() {
fmt.Println(stu.id, " ", stu.name)
}
func main() {
stu1 := Student{1, "tom"}
// 值类型调用方法
stu1.showMessage()
//调用方法修改名字()值接收者
stu1.method5(2, "修改了名字")
stu1.showMessage() //发现无法修改
// 指针类型调用方法
stu2 := &stu1
stu2.method6(2, "修改")
stu2.showMessage()
}
2 方法的继承和重写
继承主要是通过匿名结构体来实现的,实际上并不是真正意义上的继承,只是再使用起来的时候看起来像那么回事。
可以看看我前面的博客来学习关于“继承”的知识: 匿名结构体中继承
重写
如果 子类(结构体) 中的方法名与 父类(结构体) 中的方法名同名,在调用的时候是先调用子类 ( 结构 体 ) 中的方法,这就方法的重写。所谓的重写:就是子类 ( 结构体 ) 中的方法,将父类中的相同名称的方法的功能重新给改写。
package main
import "fmt"
type Person struct {
Name string
Age int
}
func (P Person) Speak() {
fmt.Printf("我是%s,今年%d岁了\n", P.Name, P.Age)
}
type Stu struct {
Person
Score float32
}
func (S Stu) Speak() {
fmt.Printf("我是%s,今年%d岁了,得了%f分\n", S.Name, S.Age, S.Score)
}
func main() {
person1 := Person{"zhangsan", 19}
person1.Speak()
stu1 := Stu{Person{"tom", 11}, 90.2}
stu1.Speak()
}
3. 接口的定义与实现
接口是什么:
- 接口是一组方法签名(就是定义一个接口,在接口的肚子里面放上一个函数 指定这个函数的形参和返回值然后在结构体中有这个特定的函数后就可以 使用接口了
)。当一个类型为接口中的所有方法提供定义时,它被称为实现该接口- Interface{} 可以理解成空接口,可以接收任意类型的参数
接口的实现:
type Animal interface {
GetName() string
}
//只要是实现了方法体GetName的结构体都是实现了Animal这个接口
代码示例:
package main
import "fmt"
/*
type 接口名 interface{
方法声明
方法名(参数)返回值
}
*/
//定义一个接口
type Humaner interface {
SayHi()
}
type Person2 struct {
Name string
Age int
}
type Teacher struct {
Person2
Subject string
}
type Student2 struct {
Person2
Score int
}
//Teacher 实现了Humaner接口
func (t *Teacher) SayHi() {
fmt.Printf("大家好,我是%s,我今年%d岁,我教%s\n", t.Name, t.Age, t.Subject)
}
//stu也实现了humaner接口
func (s *Student2) SayHi() {
fmt.Printf("大家好,我是%s,我今年%d岁,我的成绩%d\n", s.Name, s.Age, s.Score)
}
func main0401() {
//tea := Teacher{Person2{"张三", 33}, "go语言开发"}
stu := Student2{Person2{"木子", 18}, 100}
//创建接口类型变量
var h Humaner
//将对象的地址赋值给接口类型
h = &stu
//通过接口调用
h.SayHi()
}
//多态 将接口类型作为函数参数
func SayHi(h Humaner) {
h.SayHi()
}
func main() {
//初始化对象
tea := Teacher{Person2{"李四", 33}, "go语言开发"}
stu := Student2{Person2{"木子", 18}, 100}
//test:= struct {}{}
SayHi(&stu)
SayHi(&tea)
}
接口接收参数的类型判断
接口可能为 nil ,所以需要做 nil 判断func E(x interface{}) { if x == nil { fmt.Println("empty interface") return } fmt.Println("non-empty interface") } func main() { var x *int = nil E(x) }
4. 接口类型断言
package main
import "fmt"
type people struct {
Name string
}
func main0501() {
var i interface{} = &people{"jack"}
//类型断言
if v, ok := i.(*people); ok {
fmt.Println(v.Name)
} else {
fmt.Println("类型匹配失败")
}
}
func main() {
var i interface{} = people{"李四"}
switch i.(type) {
case people:
fmt.Println("people")
case *people:
fmt.Println("*people")
default:
fmt.Println("类型匹配失败")
}
}