Go-方法-接口-异常处理-错误处理

 方法

什么是方法?

  方法其实就是一个函数,在 func 这个关键字和方法名中间加入了一个特殊的接收器类型。接收器可以是结构体类型或者是非结构体类型。接收器是可以在方法的内部访问的。

package main

import "fmt"

type Person struct {
    name string
    age int
    sex int
}
// 语法
//func (a Person) getName  {
//
//}
//方法是给对象调用的
//给Person结构体加一个打印名字的方法
func (a Person)printName()  {
    fmt.Println(a.name)
}
func main()  {
    p:=Person{name:"GAI"}
    p.printName()
}

>>>GAI

为什么我们已经有函数了还需要方法呢?

  针对指针类型的数据时,方法获取元素比函数更强大。

package main
import "fmt"
//方法     其实就是一个函数
type Person struct {
    name string
    age int
    sex int
}
//语法
//func (a Person) getName()  {
//
//}
//方法给对象用
//给Person结构体加一个打印名字的方法
func (a Person)printName()  {
    fmt.Println(a.name)
}
//func (a Person)changeName(name string)  {
//    a.name=name
//    fmt.Println(a)
//}

func (a *Person)changeName(name string)  {
    a.name=name
    fmt.Println(a)
}
//func printName(a Person)  {
////    fmt.Println(a.name)
////}
////func printName(a *Person)  {
////    fmt.Println(a.name)
////}
func main() {
    var p *Person=&Person{name:"lqz"}
    //这种也可以,go给你处理了
    var p Person=Person{name:"lqz"}
    p.changeName("egon")
    fmt.Println(p)
    p.printName()

    //为什么我们已经有函数了还需要方法呢
    //执行函数
    //printName(p)
    //printName(&p)

}

指针接收器与值接收器

  到目前为止,我们只看到了使用值接收器的方法。还可以创建使用指针接收器的方法。值接收器和指针接收器之间的区别在于,

在指针接收器的方法内部的改变对于调用者是可见的,然而值接收器的情况不是这样的。让我们用下面的程序来帮助理解这一点。

    //指针接收器与值接收器
    //func (值)changeName(name string):在内部修改值,不会影响外部的值
    //func (指针)changeName(name string):在内部修改值,会影响外部的值

那么什么时候使用指针接收器,什么时候使用值接收器?

//那么什么时候使用指针接收器,什么时候使用值接收器
    //想修改原值,就用指针接收器
    //匿名字段的方法

匿名字段的方法

  属于结构体的匿名字段的方法可以被直接调用,就好像这些方法是属于定义了匿名字段的结构体一样。

//匿名字段的方法
package main

import "fmt"

//方法     其实就是一个函数

type Person1 struct {
    name string
    age int
    sex int
    Hobby
}
type Hobby struct {
    id int
    hobbyname string
}

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)
}

func main() {
    //p:=Person1{name:"lqz",Hobby:Hobby{id:10}}
    //
    ////正常操作
    ////p.Hobby.printHobbyId()
    ////非正常操作  方法也提升了
    //p.printHobbyId()




}

在方法中使用值接收器 与 在函数中使用值参数;在方法中使用指针接收器 与 在函数中使用指针参数

  当一个函数有一个值参数,它只能接受一个值参数。

  当一个方法有一个值接收器,它可以接受值接收器和指针接收器。

package main

import "fmt"

//在方法中使用值接收器 与 在函数中使用值参数
//在方法中使用指针接收器 与 在函数中使用指针参数

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)
    //不管是指针接收器还是值接收器,都可以使用值来调用
    //不管是指针接收器还是值接收器,都可以使用指针来调用
    //函数中,是什么参数,就得传什么参数

}

在非结构体上的方法

package main
import "fmt"
//在非结构体上的方法

//重命名
type MyInt int

func (i *MyInt)add()  {
    (*i)++
    fmt.Println(*i)
}
func main() {
    var a MyInt=10
    a.add()
    fmt.Println(a)
}

接口

什么是接口?

  在面向对象的领域里,接口一般这样定义:接口定义一个对象的行为。接口只指定了对象应该做什么,至于如何实现这个行为(即实现细节),则由对象本身去确定。

在 Go 语言中,接口就是方法签名(Method Signature)的集合。当一个类型定义了接口中的所有方法,我们称它实现了该接口。这与面向对象编程(OOP)的说法很类似。接口指定了一个类型应该具有的方法,并由该类型决定如何实现这些方法

例如,WashingMachine 是一个含有 Cleaning() 和 Drying() 两个方法的接口。任何定义了 Cleaning() 和 Drying() 的类型,都称它实现了 WashingMachine 接口。

类似Python中的接口,定义一个接口,继承可以实现不同的方法,.属性即可调用接口中的属性方法。

package main

import "fmt"

//接口
//接口是一系列方法的集合
//语法
//type 接口名 interface{
//    方法一
//  方法二
//}
//定义了一个鸭子接口
type Duck interface {
    run()
    speak()
}
//结构体实现该接口(只要实现了接口中的所有方法,该结构体就叫实现了Duck接口)
//侵入式接口和非侵入式接口(了解)
//定义普通鸭子结构体
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,"我嘎嘎说话")
}

func main() {
    pD:=PDuck{name:"水鸭子"}
    tD:=TDuck{name:"唐老鸭"}
    //写一个函数,让鸭子说话,不管是唐老鸭还是普通鸭子
    //speak(pD)
    //speak(tD)
    //var d Duck
    //d=pD
    //d=tD
    //fmt.Println(d)
    //问题研究:我想在函数中拿出唐老鸭的wife属性
    speak(tD)
    speak(pD)
}
//func speak(p PDuck)  {
//    p.speak()
//}
//func speak2(p TDuck)  {
//    p.speak()
//}
//func speak(p Duck)  {
//    p.speak()
//}
//我想在函数中拿出唐老鸭的wife属性
//func speak(p Duck)  {
//    //类型断言,我断言你是TDuck类型,如果没有问题,转成TDuck类型
//    a:=p.(TDuck)
//    fmt.Println(a.wife)
//    p.speak()
//}

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)


    }
}

空接口

  没有包含方法的接口称为空接口。空接口表示为 interface{}。由于空接口没有方法,因此所有类型都实现了空接口。

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("我不知道你是什么类型")

    }
}

函数接收空接口作为参数,因此,可以给这个函数传递任何类型。

类型断言

  类型断言用于提取接口的底层值(Underlying Value)。

类型选择(Type Switch)

  类型选择用于将接口的具体类型与很多 case 语句所指定的类型进行比较。它与一般的 switch 语句类似。唯一的区别在于类型选择指定的是类型,而一般的 switch 指定的是值。

类型选择的语法类似于类型断言。类型断言的语法是 i.(T),而对于类型选择,类型 T 由关键字 type 代替。

接口的其他方法:

实现多个接口

类型可以实现多个接口。我们看看下面程序是如何做到的。

package main

import "fmt"

//实现多个接口
//type SalaryCalculator interface {
//    DisplaySalary()
//}
//
//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
//}
//
//func main() {
//    e := Employee {
//        firstName: "Naveen",
//        lastName: "Ramanathan",
//        basicPay: 5000,
//        pf: 200,
//        totalLeaves: 30,
//        leavesTaken: 5,
//    }
//    var s SalaryCalculator = e
//    s.DisplaySalary()
//    var l LeaveCalculator = e
//    fmt.Println("
Leaves left =", l.CalculateLeavesLeft())
//}

//接口的零值 nil  接口是引用类型
type Describer interface {
    Describe()
}

func main() {
    var d1 Describer
    if d1 == nil {
        fmt.Println("xxxx")
    }
}

接口的嵌套

  尽管 Go 语言没有提供继承机制,但可以通过嵌套其他的接口,创建一个新接口。

//接口嵌套
type SalaryCalculator interface {
    DisplaySalary()
}

type LeaveCalculator interface {
    CalculateLeavesLeft() int
}

type EmployeeOperations interface {
    SalaryCalculator
    LeaveCalculator
}

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
}

func main() {
    e := Employee {
        firstName: "Naveen",
        lastName: "Ramanathan",
        basicPay: 5000,
        pf: 200,
        totalLeaves: 30,
        leavesTaken: 5,
    }
    var empOp EmployeeOperations = e
    empOp.DisplaySalary()
    fmt.Println("
Leaves left =", empOp.CalculateLeavesLeft())
}

接口的零值

  接口的零值是 nil。对于值为 nil 的接口,其底层值(Underlying Value)和具体类型(Concrete Type)都为 nil

//接口的零值 nil  接口是引用类型
type Describer interface {
    Describe()
}

func main() {
    var d1 Describer
    if d1 == nil {
        fmt.Println("xxxx")
    }
}

异常处理

  错误表示程序中出现了异常情况。比如当我们试图打开一个文件时,文件系统里却并没有这个文件。这就是异常情况,它用一个错误来表示。

在 Go 中,错误一直是很常见的。错误用内建的 error 类型来表示。

就像其他的内建类型(如 intfloat64 等),错误值可以存储在变量里、作为函数的返回值等等。

总结:

//异常处理
//defer  panic  recover

//defer 表示延迟调用,即便程序出现严重错误,也会执行 //panic 就是python中的raise(主动抛出异常) //recover 恢复程序,继续执行

常见异常处理的方法:

package main

import "fmt"
func main() {
//先注册,后调用 //defer fmt.Println("xxxx") //defer fmt.Println("yyy") f1() f2() f3() } func f1() { fmt.Println("f1...") } func f2() { defer func() { if a:=recover();a!=nil{
//a 如果不等于nil,表示程序出了异常,a 就是异常信息 //a 等于nil,表示没有异常 //fmt.Println("出错了")

fmt.Println(a) } //用于会被执行(相当于finally) }() fmt.Println("f2...") //var a =make([]int,3,3) //fmt.Println(a[4]) panic("你给我出去") } func f3() { fmt.Println("f3...") }

 错误处理

   错误表示程序中出现了异常情况。比如当我们试图打开一个文件时,文件系统里却并没有这个文件。这就是异常情况,它用一个错误来表示。

在 Go 中,错误一直是很常见的。错误用内建的 error 类型来表示。

就像其他的内建类型(如 intfloat64 等),错误值可以存储在变量里、作为函数的返回值等等。

package main

import (
    "errors"
    "fmt"
)

//错误

func circleArea(radius int) (int, error) {
    if radius < 0 {
        return 0, errors.New("错误信息")
        //panic("xddd")
    }
    return 100, nil
}

func main() {
    a,_:=circleArea(-10)
    if err!=nil{
        fmt.Println(err)
    }
    //fmt.Println(err)
    fmt.Println(a)
    _,err:=fmt.Println()
    if err!=nil{
        fmt.Println("打印出错")
    }
}

 主动的返回error

  

  

原文地址:https://www.cnblogs.com/Gaimo/p/12031291.html