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("\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
类型来表示。
就像其他的内建类型(如 int
、float64
等),错误值可以存储在变量里、作为函数的返回值等等。
总结:
//异常处理
//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
类型来表示。
就像其他的内建类型(如 int
、float64
等),错误值可以存储在变量里、作为函数的返回值等等。
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-方法-接口-异常处理-错误处理的更多相关文章
- Oracle 11g RAC环境下Private IP修改方法及异常处理
Oracle 11g RAC环境下Private IP修改方法及异常处理 Oracle 11g RAC环境下Private IP修改方法及异常处理 一. 修改方法 1. 确认所有节点CRS服务以启动 ...
- Java异常处理错误
Java异常处理错误 研究发现,在编译阶段的最佳时机错误,序之前.然而,编译期间并不能找出全部的错误,余下的问题必须在执行阶段解决.这就须要错误源通过某种方式把适当的信息传给某个接收者,该接收者知道怎 ...
- go 函数 方法 接口
概论 函数 方法 接口 概论 方法在编译时静态绑定,依托于具体的类型 接口对应的方法是在运行时动态绑定 进程内初始化顺序 初始化导入包的常量和变量(可以导出的变量)--->包的init函数,不同 ...
- 后端API接口的错误信息返回规范
前言 最近我司要制定开发规范.在讨论接口返回的时候,后端的同事询问我们前端,错误信息的返回,前端有什么意见? 所以做了一些调研给到后端的同事做参考. 错误信息返回 在使用API时无可避免地会因为各种情 ...
- python 处理protobuf 接口常见错误
python 处理protobuf 接口常见错误 1.问题 : Assignment not allowed to repeated field '> http://www.coin163.co ...
- 黑盒测试用例设计方法&理论结合实际 -> 错误推断法
一 概念 基于经验和直觉推测程序中所有可能存在的各种错误, 从而有针对性的设计测试用例的方法. 二 错误推断法的应用 基本思想:列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据他们选择测试 ...
- 解决和排查 "必须使用适当的属性和方法修改 User-Agent" 错误时遇到的一些坑
解决 必须使用适当的属性和方法修改 User-Agent 错误 问题描述:近在项目中有一个需求为需要在 Http 的Header里面添加一个User-Agent参数,当请求时.项目本身的目标框架是 . ...
- 在执行context.getContentResolver.query()方法时出现错误。
1. 在执行context.getContentResolver.query()方法时出现错误. 07-15 18:46:13.470: E/AndroidRuntime(13624): FATAL ...
- Saiku ui-settings接口404错误避免(二十九)
Saiku ui-settings接口404错误避免 自己手动编译的saiku ,不知道为什么前端总是报错 /saiku/rest/saiku/info/ui-settings 404NotFo ...
随机推荐
- idea 将java 项目 打包成jar包
记录一下,防止忘记.ps : 请忽略这个是web项目 1.idea 打包jar包 (1)首先打开Project Structure,选中Artifacts (2)点击绿色加号,选中jar ,然后选中f ...
- 051-PHP求余运算
<?php $x=10%5; //进行求余运算 $y=10%3; //进行求余运算 $z=10%6; //进行求余运算 echo $x; //输出变量x的值 echo $y; //输出变量y的值 ...
- Java IO流学习总结(转)
原文地址:http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 ...
- Codeforces 460C 二分结果+线段树维护
发现最近碰到好多次二分结果的题目,上次多校也是,被我很机智的快速过了,这个思想确实非常不错.在正面求比较难处理的时候,二分结果再判断是否有效往往柳暗花明. 这个题目给定n个数字的序列,可以操作m次,每 ...
- 控制数据的小数位数 java / js
//java一般控制格式都是通过 DecimalFormat 来控制的.下边是个例子. import java.text.DecimalFormat; public class ControlBit ...
- python中的__code__
简单总结几个常用的__code__的用法: (1)func.__code__.co_argcount:返回函数的参数个数,这里的参数个数不包含*args与**kwargs,具体来讲就是*args前的参 ...
- Python MySQL 教程
章节 Python MySQL 入门 Python MySQL 创建数据库 Python MySQL 创建表 Python MySQL 插入表 Python MySQL Select Python M ...
- 实验3- 熟悉常用的 HBase 操作
石家庄铁道大学信息科学与技术学院 实验报告 2018年----2019年 第一学期 题目: 熟悉常用的 HBase ...
- P5091 【模板】欧拉定理(欧拉降幂)
P5091 [模板]欧拉定理 以上3张图是从这篇 博客 里盗的,讲的比较清楚. #include<bits/stdc++.h> using namespace std; typedef l ...
- 每天一点点之 taro 框架开发 - 事件处理与样式表
1.方法调用 state = { name:'张三' } test(){ this.state.name } <button onClick={ this.test.bind(this) } / ...