连载二:go结构体、函数、接口、反射

连载二: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)

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值