方法
1.什么是方法
方法其实就是一个函数,在 func
这个关键字和方法名中间加入了一个特殊的接收器类型。接收器可以是结构体类型或者是非结构体类型。接收器是可以在方法的内部访问的。
func (t Type) methodName(parameter list) {
}
2.方法的定义使用
1.方法绑定给结构体 //1.定义结构体 type Person struct { name string age int sex int } //2.给Person结构体加一个打印名字的方法 func (a Person)printName() { fmt.Println(a.name) //接收器直接使用结构体内属性 } //3.main函数中使用 var p *Person=&Person{name:"lqz"} //实例化 p.printName() //调用方法
3.指针接收器和值接收器
1.值接收器和指针接收器的区别在于方法接收器的类型; func (a Person)changeName(name string) //值接收器 unc (a *Person)changeName(name string) //指针接收器
2.
//func (值)changeName(name string):在内部修改值,不会影响外部的值
//func (指针)changeName(name string):在内部修改值,会影响外部的值
示例:
1.值接收器方法 //1.定义结构体 type Person struct { name string age int sex int } //2.绑定方法 func (a Person)changeName(name string) { a.name=name fmt.Println(a) //{egon 0 0} } //3.main函数调用 p.changeName("egon") fmt.Println(p) //{lqz 0 0} 2.指针接收器方法 //1.定义结构体 type Person struct { name string age int sex int } //2.绑定方法 func (a *Person)changeName(name string) { a.name=name fmt.Println(a) //&{egon 0 0} } //3.main函数调用 //var p *Person=&Person{name:"lqz"} //这种也可以,go给你处理了 var p Person=Person{name:"lqz"} p.changeName("egon") fmt.Println(p)//{egon 0 0}
4.匿名字段提升方法
前提:属于结构体的匿名字段的方法可以被直接调用,就好像这些方法是属于定义了匿名字段的结构体一样。匿名才会提升不匿名不会提升。如果子类有就用自己的,没有用父类的
1.定义 type Person1 struct { name string age int sex int Hobby } type Hobby struct { id int hobbyname string } 2.绑定方法 func (h Hobby)printHobbyId() { fmt.Println(h.id) } func (a Person1)printName() { fmt.Println(a.name) } func (a Person1)printHobbyId() { fmt.Println("我重写了") //重用父类的方法 //a.Hobby.printHobbyId() fmt.Println(a.Hobby.id) } 3.main函数中 //p:=Person1{name:"lqz",Hobby:Hobby{id:10}} // ////正常操作 ////p.Hobby.printHobbyId() ////非正常操作 方法也提升了 //p.printHobbyId()
5.补充
type Person2 struct { name string age int sex int } //方法中使用值接收器 func (a Person2)printName() { fmt.Println(a.name) } //方法中使用指针接收器 func (a *Person2)printName2() { fmt.Println(a.name) } //函数中使用值参数 func printName(a Person2) { fmt.Println(a.name) } //在函数中使用指针参数 func printName2(a *Person2) { fmt.Println(a.name) } func main() { //p:=&Person2{name:"lqz"} //调用值接收器 //p.printName() //调用指针接收器 //p.printName2() //调用值函数 //printName(p) //调用指针函数 //printName2(&p) //不管是指针接收器还是值接收器,都可以使用值来调用 //不管是指针接收器还是值接收器,都可以使用指针来调用 //函数中,是什么参数,就得传什么参数
接口
1.什么是接口
接口是一系列方法的集合。
2.接口定义和类型及零值
1.
type 接口名 interface{
方法一
方法二
}
2.接口类型:接口名
3.接口零值:nil
3.定义接口使用和类型断言
1.第一步 //1.定义了一个鸭子接口 type Duck interface { run() speak() } //2.第二不:定义普通鸭子结构体 type PDuck struct { name string age string } func (p PDuck)run() { fmt.Println("我是普通鸭子,我名字叫",p.name,"我走路歪歪扭扭") } func (p PDuck)speak() { fmt.Println("我是普通鸭子,我名字叫",p.name,"我嘎嘎说话") } //定义一个唐老鸭,实现鸭子接口 type TDuck struct { name string age string wife bool } func (p TDuck)run() { fmt.Println("我是普通鸭子,我名字叫",p.name,"我走路歪歪扭扭") } func (p TDuck)speak() { fmt.Println("我是普通鸭子,我名字叫",p.name,"我嘎嘎说话") } //3.第三步:main函数中使用 pD:=PDuck{name:"水鸭子"} tD:=TDuck{name:"唐老鸭"} speak(pD) speak(tD) //4.第四步:main函数外,p为接口Duck为接口类型即接口名但可以通过结构体对象 func speak(p Duck){ p.speak() } //5.类型断言主要是为了判断结构体对象是否是某个结构体类型 方式1提前知道类型: func speak(p Duck) { // 类型断言,我断言你是TDuck类型,如果没有问题,转成TDuck类型,然后获取属性值 a:=p.(TDuck) fmt.Println(a.wife) p.speak() } 方式2提前不知道类型: func speak(p Duck) { switch a:=p.(type) { case PDuck: //判断好了,你是普通鸭子,把鸭子名字拿出来 fmt.Println("你是普通鸭子") fmt.Println(a.name) case TDuck: //判断好了,你是唐老鸭,把唐老鸭的wife拿出来 fmt.Println("你是唐老鸭") fmt.Println(a.wife) } }
4.空接口和匿名空接口
1.什么是空接口和匿名空接口
1.没有方法的接口叫做空接口 2.没有名字和方法的接口叫做匿名空接口 3.这2者可以接受任意的数据类型
2.示例
package main import "fmt" //空接口(一个方法都没有) //匿名空接口 //所有的数据类型都实现了空接口 type Empty interface { } type TDuck2 struct { name string age string wife bool } func main() { test(1) test("ssss") test(TDuck2{}) test(10.45) var a Empty =1 var b Empty ="dddd" } //func test(a Empty) { // fmt.Println(a) //} func test(a interface{}) { switch a.(type) { case int: fmt.Println("你是int类型") case string: fmt.Println("你是string ") case TDuck2: fmt.Println("你是唐老鸭") default: fmt.Println("我不知道你是什么类型") } }
5.多接口
1.什么是多接口
指的是一个结构体绑定多个方法,且这些方法属于不同的接口
2.示例:
//接口1 type SalaryCalculator interface { DisplaySalary() } //接口2 type LeaveCalculator interface { CalculateLeavesLeft() int } //定义结构体 type Employee struct { firstName string lastName string basicPay int pf int totalLeaves int leavesTaken int } //结构体绑定方法且方法属于不同的接口 func (e Employee) DisplaySalary() { fmt.Printf("%s %s has salary $%d", e.firstName, e.lastName, (e.basicPay + e.pf)) } func (e Employee) CalculateLeavesLeft() int { return e.totalLeaves - e.leavesTaken } //main函数使用 e := Employee { firstName: "Naveen", lastName: "Ramanathan", basicPay: 5000, pf: 200, totalLeaves: 30, leavesTaken: 5, } var s SalaryCalculator = e //var 变量名 接口名 = 结构体对象 s.DisplaySalary() var l LeaveCalculator = e
6.接口的嵌套
type SalaryCalculator interface {
DisplaySalary()
}
type LeaveCalculator interface {
CalculateLeavesLeft() int
}
type EmployeeOperations interface {
SalaryCalculator
LeaveCalculator
}
异常处理
1.常用方法
defer panic recover 1.defer :延迟调用(同等级所有程序执行完之后在执行,多个defer时,从下往上执行),即便程序出现错误,也会立马执行 2.panic 就是python中的raise(主动抛出异常) 3.recover :检测到程序出现错误时,恢复程序,继续执行
2.异常处理模板
1.语法: defer func() { if a:=recover();a!=nil{ //a 如果不等于nil,表示程序出了异常,a 就是异常信息 //a 等于nil,表示没有异常 //fmt.Println("出错了") fmt.Println(a) } //用于会被执行(相当于finally) fmt.Println("永远都会执行") }() 2.示例: func f2() { defer func() { if a:=recover();a!=nil{ //a 如果不等于nil,表示程序出了异常,a 就是异常信息 //a 等于nil,表示没有异常 //fmt.Println("出错了") fmt.Println(a) } //用于会被执行(相当于finally) }()
错误
1.第一种方式不处理
import ( "errors" "fmt" ) //1.调用:注意其中一个变量是来接收错误信息的 a,err:=circleArea(-10) //处理错误信息 if err!=nil{ fmt.Println(err) } //fmt.Println(err) fmt.Println(a)//2.语法:errors.New("错误信息") func circleArea(radius int) (int, error) { if radius < 0 { return 0, errors.New("错误信息") //panic("xddd") } return 100, nil }
2.主动抛出错误(不建议使用)
panic("错误信息")