连载二:go结构体、函数、接口、反射
结构体方法
方法类型
值类型:
func (this Object) add () {}
指针类型:
func (this *Object) add () {}
鉴于性能的原因, 最常见的是一个指向的指针(因为我们不想要一个实例的拷贝,如果按值调用的话就会是这样),特别是在 类型是结构体时,就更是如此了。指针方法和值方法都可以在指针或非指针上被调用
结构体方法
func (this *OperationAdd) Exe(a int, b int) int {
return a + b
}
func (receiver Calculate) Plus() int {
return receiver.Number1 + receiver.Number2
}
函数特点
无需声明原型
支持不定变参
支持多返回值
支持命名返回参数
支持匿名函数和闭包
函数也是一种类型,一个函数可以赋值给变量
不支持 嵌套 (nested) 一个包不能有两个名字一样的函数
不支持 重载 (overload)
不支持 默认参数 (default parameter)。
函数定义
func function_name( [parameter list] ) [return_types] {
函数体
}
// 不定参数
func myfunc(args ...int) { //0个或多个参数
}
func add(a int, args…int) int { //1个或多个参数
}
匿名函数
n := func(a int) int {
a++
return a
}
fmt.Println(n(1))
碰巧匿名函数与上了切片
fns := [](func(x int) int){
func(x int) int { return x + 1 },
func(x int) int { return x + 2 },
}
println(fns[0](100))
闭包
func main() {
test()()
}
func test() func() {
return func() {
fmt.Println("test func ()")
}
}
闭包
// 需要注意如下代码
func a() func() {
i := 0
b := func() {
i++
fmt.Println(i)
}
return b
}
func main() {
c := a()
c()
c()
}
defer与panic
defer特性
1. 关键字 defer 用于注册延迟调用。
2. 这些调用直到 return 前才被执。因此,可以用来做资源清理。
3. 多个defer语句,按先进后出的方式执行。
4. defer语句中的变量,在defer声明时就决定了。
defer用途
1.关闭文件句柄
2. 锁资源释放
3. 数据库连接释放
panic用途
1、内置函数
2、假如函数F中书写了panic语句,会终止其后要执行的代码,在panic所在函数F内如果存在要执行的defer函数列表,按照defer的逆序执行
3、返回函数F的调用者G,在G中,调用函数F语句之后的代码不会执行,假如函数G中存在要执行的defer函数列表,按照defer的逆序执行
4、直到goroutine整个退出,并报告错误
结构体
结构体定义
type 类型名 struct {
字段名 字段类型
字段名 字段类型
…
}
结构体嵌套
//address 地址结构体
type address struct {
city string
}
//User 用户结构体
type user struct {
name string
sex string
addr address //匿名结构体
}
结构体继承
type User struct {
Name string
Sex string
}
type Teacher struct {
user User
}
type Manger struct {
User
}
结构体方法
类型 T 方法集包含全部 receiver T 方法。
类型 *T 方法集包含全部 receiver T + *T 方法。
如类型 S 包含匿名字段 T,则 S 和 *S 方法集包含 T 方法。
如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 T + *T 方法。
不管嵌入 T 或 T,S 方法集总是包含 T + *T 方法。
练习
package main
import "fmt"
func main() {
// fmt.Println("hello word")
// arr := index
// fmt.Println(arr)
//sum(1, 23, 4, 56)
//fmt.Println(1, 23, 4, 56)
//匿名函数
// test := func(k int) {
// fmt.Println("this is 闭包", k)
// }
// test(8)
//闭包
//tests()() //这样调用打印出来就是1
// tests := tests()
// tests() //1
// tests() //2
// tests() //3 //这样调用打印出来的就会累加1 2 3
//延迟执行
//def()
//异常
//pa()
//recover捕获异常
defer func() {
fmt.Println("捕获异常:", recover())
}()
pa()
}
// 闭包
func tests() func() {
i := 0
return func() {
i++
fmt.Println(i)
}
}
func index() {
fmt.Println("kk")
}
// 不定传参
func sum(arr ...int) {
fmt.Println(arr)
}
func def() {
//延迟执行,在方法或函数执行后执行,在执行顺序上是先写的最后执行,后面在前执行
defer index() //最后执行
defer sum(1, 2, 3) //第二执行
fmt.Println("这里是def") //最新执行
}
func pa() {
panic("这里是手动提示异常")
}
接口
接口类型变量
type ArithmeticInterface interface {// … }
var ari src.ArithmeticInterface
if arg4 == "f" || arg4 == "float" {
// 浮点型计算
ari, err = src.NewArithmeticFloat(arg2, arg3)
} else {
// 整型运算
ari, err = src.NewArithmeticInt(arg2, arg3)
}
#练习
package main
import "fmt"
//接口
type Pay interface {
Order(id int) int
Callback()
}
type WeChat struct {
}
type Ali struct {
}
func (w *WeChat) Order(id int) int {
return 200
}
func (w *WeChat) Callback() {
}
func (w *Ali) Order(id int) int {
return 300
}
// 支付方法
func PayMethod(pay Pay, id int) {
fmt.Println(pay.Order(id))
}
类型判断
利用type进行类判断类型
var k interface{}
k = 10
switch k.(type) {
case int:
fmt.Println("int")
case string:
fmt.Println("string")
}
简单工厂练习
package main
//接口 计算器接口
type OperationInterface interface {
Exe(a, b int) int
}
//加减乘除结构体
type OperationAdd struct{}
type OperationSub struct{}
type OperationMul struct{}
type OperationDiv struct{}
//实现接口计算方法
func (o *OperationAdd) Exe(a, b int) int {
return a + b
}
func (o *OperationSub) Exe(a, b int) int {
return a - b
}
func (o *OperationMul) Exe(a, b int) int {
return a * b
}
func (o *OperationDiv) Exe(a, b int) int {
return a / b
}
//简单工厂
func OperationFactory(oper string) OperationInterface {
switch oper {
case "+":
return &OperationAdd{}
case "-":
return &OperationSub{}
case "*":
return &OperationAdd{}
case "/":
return &OperationDiv{}
}
return nil
}
//简单工厂调用
sum := OperationFactory("+").Exe(10, 10)
fmt.Println(sum)
注册工厂练习
package main
var opers map[string]OperationInterface
// 利用初始化方法把内容注册进map中
func init() {
opers = make(map[string]OperationInterface, 0)
opers["+"] = &OperationAdd{}
opers["-"] = &OperationSub{}
opers["*"] = &OperationMul{}
opers["/"] = &OperationDiv{}
}
// 注册工厂调用
func OperationsFactory(oper string) OperationInterface {
return opers[oper]
}
main中调用
//注册工厂
sum := OperationsFactory("+").Exe(20, 10)
fmt.Println(sum)
//测试
func TestOper(t *testing.T) {
num1 := 1
num2 := 2
flag := "+"
rel := OperationsFactory(flag).Exe(num1, num2)
t.Log(rel)
}
go test -v
反射
根据反射实现注册工厂构造函数
operation.go
package main
//接口 计算器接口
type OperationInterface interface {
Exe() int
}
//父类结构体
type Operation struct {
num1 int
num2 int
}
//对私有变量设置值
func (o *Operation) SetNum1(num int) {
o.num1 = num
}
func (o *Operation) SetNum2(num int) {
o.num2 = num
}
//获取私有变量
func (o *Operation) GetNum1() int {
return o.num1
}
func (o *Operation) GetNum2() int {
return o.num2
}
//加减乘除 子类结构体且不对外访问时
type OperationAdd struct {
oper *Operation
}
type OperationSub struct {
oper *Operation
}
type OperationMul struct {
oper *Operation
}
type OperationDiv struct {
oper *Operation
}
//加法构造方法
func NewAdd(num1, num2 int) *OperationAdd {
return &OperationAdd{
oper: &Operation{
num1: num1,
num2: num2,
},
}
}
//减法构造方法
func NewSub(num1, num2 int) *OperationSub {
return &OperationSub{
oper: &Operation{
num1: num1,
num2: num2,
},
}
}
//乘构造方法
func NewMul(num1, num2 int) *OperationMul {
return &OperationMul{
oper: &Operation{
num1: num1,
num2: num2,
},
}
}
//除法构造方法
func NewDiv(num1, num2 int) *OperationDiv {
return &OperationDiv{
oper: &Operation{
num1: num1,
num2: num2,
},
}
}
//实现接口计算方法
func (o *OperationAdd) Exe() int {
return o.oper.num1 + o.oper.num2
}
func (o *OperationSub) Exe() int {
return o.oper.num1 - o.oper.num2
}
func (o *OperationMul) Exe() int {
return o.oper.num1 * o.oper.num2
}
func (o *OperationDiv) Exe() int {
return o.oper.num1 / o.oper.num2
}
//简单工厂
func OperationFactory(oper string) OperationInterface {
switch oper {
case "+":
return &OperationAdd{}
case "-":
return &OperationSub{}
case "*":
return &OperationAdd{}
case "/":
return &OperationDiv{}
}
return nil
}
oper.go
package main
import (
"fmt"
"reflect"
)
var opers map[string]interface{}
// 利用初始化方法把内容注册进map中
func init() {
opers = make(map[string]interface{}, 0)
opers["+"] = NewAdd //把方法赋值给变量名
opers["-"] = NewSub //把构造函数当做方法
opers["*"] = NewMul //运用反射实现
opers["/"] = NewDiv //
}
// 反射实现注册工厂调用
func OperationsFactory(num1, num2 int, flag string) OperationInterface {
oper := opers[flag]
//根据类型得到反射的结构体对象value
valueOper := reflect.ValueOf(oper) //reflect.value
fmt.Println("reflect.ValueOf(oper):", valueOper)
fmt.Printf("type:%T \n", valueOper)
//定义方法参数
args := []reflect.Value{
//传参,没参时为空
reflect.ValueOf(num1),
reflect.ValueOf(num2),
}
//根据类型调用函数或方法 相当于执行了php call_user_func方法,这是执行了构造函数NewAdd(num1,num2)
arrValueOper := valueOper.Call(args)[0] //返回切片,只有一个值时取0
fmt.Println("valueOper.Call:", arrValueOper)
//还是反射类型
fmt.Printf("type:%T \n", arrValueOper)
//把反射类型解析为原来类型 OperationInterface
//arrValueOper.Interface() //返回一个interface类型
//通过接口断言转为原来类型
operation := arrValueOper.Interface().(OperationInterface)
fmt.Printf("ref-type:%T \n", operation)
return operation
}
反射调用测试
func TestOper(t *testing.T) {
num1 := 1
num2 := 2
flag := "+"
//rel := OperationsFactory(flag).Exe(num1, num2)
// t.Log(rel)
rel := OperationsFactory(num1, num2, flag).Exe()
t.Log(rel)
}
反射理解
package main
import (
"fmt"
"reflect"
)
type stu struct {
name string
}
func main() {
//var i int = 10
var i string = "10"
//i := stu{name: "yzz"}
ref(i)
}
func ref(i interface{}) {
fmt.Println("i的类型:", reflect.TypeOf(i))
fmt.Println("i的数据值:", reflect.ValueOf(i))
}
反射三大原则
反射的第一法则是我们能将 Go 语言的 interface{} 变量转换成反射对象
示例:
package main
import (
"fmt"
"reflect"
)
func main() {
a := 10
fmt.Println("TypeOf : a :", reflect.TypeOf(a))
fmt.Println("ValueOf : a :", reflect.ValueOf(a))
}
反射的第二法则是我们可以从反射对象可以获取 interface{} 变量
示例:
a := 9
rv := reflect.ValueOf(a)
rvi := rv.Interface().(int) // rv.Interface() 返回是Interface{}类型,后续为断言
fmt.println(rvi)
转化过程
反射的第三法则是可以进行原值的修改
a := 9
rv := reflect.ValueOf(&a)
rv.Elem().SetInt(100)
fmt.Println(a) // 100
练习
package main
import (
"fmt"
"reflect"
)
type stu struct {
name string
age int
}
func main() {
var i int = 10
//var i string = "10"
//i := stu{name: "yzz", age: 18}
ref(i)
rv := reflect.ValueOf(&i)
rv.Elem().SetInt(100)
fmt.Println(i)
}
// 不明确传递类型
func ref(i interface{}) {
rt := reflect.TypeOf(i)
rv := reflect.ValueOf(i)
fmt.Println("i的类型:", rt)
fmt.Println("i的数据值:", rv)
fmt.Printf("type rt:%T \n", rt)
fmt.Printf("type rv:%T \n", rv)
rvi := rv.Interface()
fmt.Printf("type rvi:%T \n", rvi)
rvii := rv.Interface().(int)
fmt.Printf("type rvii:%T \n", rvii)
}