面向对象编程
- OOP思想 :拟人化思想。物以类聚. 类:抽象的模板,定义一个类(属性、方法),实例化出来一个对象-具体的。
- OOP三大特性:封装、继承、多态
- Go语言不是面向对象的编程语言,有一些机制可以实现面向对象编程的思维
- 封装:结构体封装 + 方法实现 , 模拟一个类
- 继承:匿名字段 、提升字段 (属性、方法)
- 多态:一个事务可以拥有多种形态(接口)
- 空接口 any
接口嵌套
package main
import (
"fmt"
)
type AA interface {
test1()
}
type BB interface {
test2()
}
// 接口嵌套 CC : test1()/test2()/test3()
// 如果要实现接口CC,那么需要实现这个三个方法。那这个对象就有3个接口可以转型。
type CC interface {
AA // 导入AA接口中的方法
BB
test3()
}
// 编写一个结构体实现接口CC
type Dog7 struct {
}
func (dog Dog7) test1() {
fmt.Println("test1")
}
func (dog Dog7) test2() {
fmt.Println("test2")
}
func (dog Dog7) test3() {
fmt.Println("test3")
}
func main() {
// dog 拥有4种形态: Dog7 、CC 、 BB 、 AA
var dog Dog7 = Dog7{}
dog.test1()
dog.test2()
dog.test3()
//
var a AA = dog
a.test1()
//a.test2() // 向上转型之后只能调用它自己对应的方法
var b BB = dog
b.test2()
var c CC = dog
c.test1()
c.test2()
c.test3()
}
接口断言
检查一个接口类型的变量是不是符合你的预期值。
比如:我们预期使用 test3() . 如果传递的是 a 、b 对象,我们就需要判断这个对象是否是我们预期的对象。 = 断言。
被断言的对象必须是接口类型,否则会报错
如果一个对象存在多种形态: 接口判断 登录 20个实现类 微信登录
- i.(T) 判断是否是预期接口
- swtich i.(type) 判断是否是预期的case结果
package main
import "fmt"
// 通过switch来判断 switch i.(T)
type I interface{}
// 如果断言的类型同时实现了switch 多个case匹配,默认使用第一个case
func testAsserts(i interface{}) {
// switch i.(type) 接口断言
switch i.(type) {
case string:
fmt.Println("变量为string类型")
case int:
fmt.Println("变量为int类型")
case I:
fmt.Println("变量为I类型")
case nil:
fmt.Println("变量为nil类型")
case interface{}:
fmt.Println("变量为interface{}类型")
// .....
default:
fmt.Println("未知类型")
}
}
func main() {
testAsserts("string")
testAsserts(1)
var i I // 默认值为 nil
var i2 I = 1 // 只有赋值了之后,才是对应的类型
testAsserts(i)
testAsserts(i2)
}
type 别名
- type xxx TTT 自定义类型
- type xxx = TTT 起别名
package main
import "fmt"
// var 变量 type 类型(结构体、接口、别名...)
// type的别名用法,全局变量中
// 这是定义了一个新类型 MyInt,是int转换过来的,和int一样,但是不能通int发生操作,类型不同
// MyInt int
// 创建了一种新类型!
type MyInt int
func main() {
var a MyInt = 20 // MyInt
var b int = 10 // int
// invalid operation: a + b (mismatched types MyInt and int)
//fmt.Println(a + b)
// 类型转换: T(v)
fmt.Println(int(a) + b) // 30
fmt.Printf("%T\n", a) // main.MyInt
fmt.Printf("%T\n", b) // int
// 给int起一个小名,但是它还得是int type any
var c diyint = 30
fmt.Printf("%T\n", c) // int
}
/*
type关键字的理解:
1、type 定义一个类型
- type User struct 定义结构体类型
- type User interface 定义接口类型
- type Diy (int、string、....) 自定义类型,全新的类型
2、type 起别名
- type xxx = 类型 ,将某个类型赋值给 xxx,相当于这个类型的别名
- 别名只能在写代码的时候使用,增加代码的可阅读性。
- 真实在项目的编译过程中,它还是原来的类型。
*/
异常和错误
错误与异常
错误:指的是程序中预期会发生的结果,预料之中
打开一个文件:文件正在被占用,可知的。
异常:不该出现问题的地方出现了问题,预料之外
调用一个对象,发现这个对象是个空指针对象,发生错误。
错误是业务的一部分,而异常不是。
go语言开发过程中遇到最多的代码,就是error。
需要将所有的错误情况都考虑到,并写到你的代码中。
错误 error
鼓励工程师在代码中显式的检查错误,而非忽略错误。
package main
import (
"fmt"
"os"
)
// 错误是开发中必须要思考的问题
// - 某些系统错误 ,文件被占用,网络有延迟
// - 人为错误:核心就是一些不正常的用户会怎么来给你传递参数,sql注入
func main() {
//打开一个文件 os 系统包,所有可以用鼠标和键盘能执行的事件,都可以用程序实现
// func Open(name string) (*File, error)
file, err := os.Open("aaa.txt")
// 在开发中,我们需要思考这个错误的类型 PathError
// 1、文件不存在 err
// 2、文件被占用 err
// 3、文件被损耗 err
// 调用方法后,出现错误,需要解决
if err != nil {
fmt.Println(err)
return
}
fmt.Println(file.Name())
}
// 在实际工程项目中,
// 我们希望通过程序的错误信息快速定位问题,但是又不喜欢错误处理代码写的冗余而又啰嗦。
// Go语言没有提供像Java. c#语言中的try...catch异常处理方式,
// 而是通过函数返回值逐层往上抛, 如果没有人处理这个错误,程序就终止 panic
// 这种设计,鼓励工程师在代码中显式的检查错误,而非忽略错误。
// 好处就是避免漏掉本应处理的错误。但是带来一个弊端,让代码繁琐。
// Go中的错误也是一种类型。错误用内置的error类型表示。就像其他类型的,如int, float64。
// 错误值可以存储在变量中,从函数中返回,传递参数 等等。
自己定义一个错误
package main
import (
"errors"
"fmt"
)
// 自己定义一个错误
// 1、errors.New("xxxxx")
// 2、fmt.Errorf()
// 都会返回 error 对象, 本身也是一个类型
func main() {
age_err := setAge(-1)
if age_err != nil {
fmt.Println(age_err)
}
fmt.Printf("%T\n", age_err) // *errors.errorString
// 方式二
errInfo1 := fmt.Errorf("我是一个错误信息:%d\n", 500)
//errInfo2 := fmt.Errorf("我是一个错误信息:%d\n", 404)
if errInfo1 != nil {
// 处理这个错误
fmt.Println(errInfo1)
}
}
// 设置年龄的函数,一定需要处理一些非正常用户的请求
// 返回值为 error 类型
// 作为一个开发需要不断思考的事情,代码的健壮性和安全性
func setAge(age int) error {
if age < 0 {
// 给出一个默认值
age = 3
// 抛出一个错误 errors 包
return errors.New("年龄不合法")
}
// 程序正常的结果,给这个用户赋值
fmt.Println("年龄设置成功:age=", age)
return nil
}
自定义一个错误
package main
import (
"fmt"
)
type KuangShenError struct {
msg string
code int
}
// Error() string
func (e *KuangShenError) Error() string {
// fmt.Sprintf() 返回string
return fmt.Sprintf("错误信息:%s,错误代码:%d\n", e.msg, e.code)
}
// 处理error的逻辑
func (e KuangShenError) print() bool {
fmt.Println("hello,world")
return true
}
// 使用错误测试
func test(i int) (int, error) {
// 需要编写的错误
if i != 0 {
// 更多的时候我们会使用自定义类型的错误
return i, &KuangShenError{msg: "非预期数据", code: 500}
}
// 正常结果
return i, nil
}
func main() {
i, err := test(1)
if err != nil {
fmt.Println(err)
ks_err, ok := err.(*KuangShenError)
if ok {
if ks_err.print() {
// 处理这个错误中的子错误的逻辑
}
fmt.Println(ks_err.msg)
fmt.Println(ks_err.code)
}
}
fmt.Println(i)
}