方法

什么是方法?

  方法其实就是一个函数,在 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("\nLeaves 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("\nLeaves 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

  

  

Go-方法-接口-异常处理-错误处理的更多相关文章

  1. Oracle 11g RAC环境下Private IP修改方法及异常处理

    Oracle 11g RAC环境下Private IP修改方法及异常处理 Oracle 11g RAC环境下Private IP修改方法及异常处理 一. 修改方法 1. 确认所有节点CRS服务以启动 ...

  2. Java异常处理错误

    Java异常处理错误 研究发现,在编译阶段的最佳时机错误,序之前.然而,编译期间并不能找出全部的错误,余下的问题必须在执行阶段解决.这就须要错误源通过某种方式把适当的信息传给某个接收者,该接收者知道怎 ...

  3. go 函数 方法 接口

    概论 函数 方法 接口 概论 方法在编译时静态绑定,依托于具体的类型 接口对应的方法是在运行时动态绑定 进程内初始化顺序 初始化导入包的常量和变量(可以导出的变量)--->包的init函数,不同 ...

  4. 后端API接口的错误信息返回规范

    前言 最近我司要制定开发规范.在讨论接口返回的时候,后端的同事询问我们前端,错误信息的返回,前端有什么意见? 所以做了一些调研给到后端的同事做参考. 错误信息返回 在使用API时无可避免地会因为各种情 ...

  5. python 处理protobuf 接口常见错误

    python 处理protobuf 接口常见错误 1.问题 : Assignment not allowed to repeated field '> http://www.coin163.co ...

  6. 黑盒测试用例设计方法&理论结合实际 -> 错误推断法

    一 概念 基于经验和直觉推测程序中所有可能存在的各种错误, 从而有针对性的设计测试用例的方法. 二 错误推断法的应用  基本思想:列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据他们选择测试 ...

  7. 解决和排查 "必须使用适当的属性和方法修改 User-Agent" 错误时遇到的一些坑

    解决 必须使用适当的属性和方法修改 User-Agent 错误 问题描述:近在项目中有一个需求为需要在 Http 的Header里面添加一个User-Agent参数,当请求时.项目本身的目标框架是 . ...

  8. 在执行context.getContentResolver.query()方法时出现错误。

    1. 在执行context.getContentResolver.query()方法时出现错误. 07-15 18:46:13.470: E/AndroidRuntime(13624): FATAL ...

  9. Saiku ui-settings接口404错误避免(二十九)

    Saiku ui-settings接口404错误避免 自己手动编译的saiku ,不知道为什么前端总是报错   /saiku/rest/saiku/info/ui-settings  404NotFo ...

随机推荐

  1. symbol数据类型

    symbol声明的类型独一无二 概念:表示独一无二的值,永远不相等 s1 = Symbol() s2 = Symbol() s1 !== s2 基本使用: 通过Symbol函数生成,得到一个symbo ...

  2. P1011 A+B 和 C

    转跳点:

  3. Python基础笔记:函数:调用函数、定义函数、函数的参数、递归函数

    一.定义一个求二元一次方程的根的函数 #Sublime Text import math def ee(a,b,c): delta=b*b-4*a*c if delta<0: return 'n ...

  4. 11.swoole学习笔记--进程信号触发器

    <?php //触发函数--异步执行 swoole_process::signal(SIGALRM,function(){ ; echo "$i \n"; $i++; ){ ...

  5. 五十七、SAP中关于信息框的总结

    一.事务代码SE91 二.里面有我们创建过的一个消息类Z_TIANPAN_201907_MSG 三.这个消息类中有2个内容 四.我们的代码如下 五.S001效果 六.E001和W001效果 七.I00 ...

  6. 四十三、在SAP中初始化勾选值

    一.上代码 二.运行时,勾选框会被自动勾选中 三.表单如下

  7. Python 异常处理(Try...Except)

    版权所有,未经许可,禁止转载 章节 Python 介绍 Python 开发环境搭建 Python 语法 Python 变量 Python 数值类型 Python 类型转换 Python 字符串(Str ...

  8. Newtonsoft.Json版本冲突

    如果项目中不同第三方类库分别使用了不同版本的Newtonsoft.Json,可以在配置文件中添加以下节点,将0.0.0.0-9.0.0.0此区间的Newtonsoft.Json使用全部强制指向到项目中 ...

  9. 尝试用kotlin做一个app(五)

    JSP后台管理系统 开发工具是IntelliJ IDEA+tomcat+mysql5.6.19+mysql-connector-java-5.1.48.jar+easyui+kindeditor 之前 ...

  10. SMPL模型Shape和Pose参数

    两部分 1.Pose参数 2.Shape参数 一 Pose参数 共24个关节点,对应idx从0到23,图中3个小图分别表示zero shape只有idx节点分别绕x/y/z轴旋转. 其中蓝色线表示-p ...