zoukankan      html  css  js  c++  java
  • 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

      

      

  • 相关阅读:
    HFish 源码Git下载 源码编译执行
    Windows注册表-学习总结
    利用PHPStudy搭建Xdebug调试环境
    Python3报错Crypto失败(from Crypto.Cipher import AES ModuleNotFoundError: No module named 'Crypto')
    Django后台管理admin字段控制显示长度(字段内容过长,省略号替代)
    PHP代码审计-小题一道
    golang编程-小问题
    迅雷影音播放器-ass字幕乱码-问题
    《独自等待》观影有感
    Python urllib URL 处理模块
  • 原文地址:https://www.cnblogs.com/Gaimo/p/12031291.html
Copyright © 2011-2022 走看看