Go语言学习笔记(十六)

本文介绍了Go语言中如何使用全局变量加锁避免资源争夺问题,以及深入理解反射机制。通过示例展示了如何对全局变量加锁同步改进程序,以及如何利用反射在运行时检查和修改变量的值、调用方法。同时,文章还提供了反射在遍历结构体字段、调用方法等方面的应用,并给出了实际代码示例。
摘要由CSDN通过智能技术生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档



一、使用全局变量加锁同步改进程序

未对全局变量m加锁,因此会出现资源争夺问题,代码出现错误

var(
	//声明一个全局的互斥锁
	//lock是一个全局互斥锁
	//Mutex是互斥
	myMap = make(map[int]int,10)
	lock sync.Mutex
)
func test(n int){
	res :=1
	for i :=1;i<=n;i++{
	res *=i
}
//将res放入myMap加锁
lock.Lock()
myMap[n]=res
lock.Unlock()
}

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

二、反射

go语言提供了一种机制在运行时更新和检查变量的值、调用变量的方法和变量支持的内在操作,但是在编译时并不知道这些变量的具体类型,这种机制被称为反射。反射也可以让我们将类型本身作为第一类的值类型处理。

反射是指在程序运行期对程序本身进行访问和修改的能力,程序在编译时变量被转换为内存地址,变量名不会被编译器写入到可执行部分,在运行程序时程序无法获取自身的信息。

支持反射的语言可以在程序编译期将变量的反射信息,如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息,并且有能力修改它们。
利用reflect 包来访问程序的反射信息。
在Go语言程序中,使用 reflect.TypeOf() 函数可以获得任意值的类型对象(reflect.Type)
示例

package main
import (
    "fmt"
    "reflect"
)
func main() {
    var a int
    typeOfA := reflect.TypeOf(a)
    fmt.Println(typeOfA.Name(), typeOfA.Kind())
}

得出结果为int
反射的应用情况
interface{}具体类型通过reflect.Type表示,对应值通过reflect.Value表示。 reflect.TypeOf() 和 reflect.ValueOf() 函数分别返回reflect.Type和reflect.Value,利用这两个类型我们可以实现通用逻辑。

使用反射来遍历结构体的字段,调用结构体的方法,修改结构体字段的值,并获取结构体标签的值

import (
    "fmt"
    "reflect"
)

type Student struct {
	Name string	`json:"name"`
	Sex string `json:"sex"`
	Age int `json:"age"`
	Sal float64 `json:"sal"`
}
func (s Student) GetName() string  {  
	fmt.Println("该结构体Name字段值为:",s.Name)
	return s.Name
}
func (s *Student) Set(newName string,newAge int,newSal float64){  
	s.Name = newName
	s.Age = newAge
	s.Sal = newSal
	s.Print()
}

func (s Student) Print()   { //第1个方法
	fmt.Println("调用 Print 函数输出结构体:",s)
}

//反射获取结构体字段、方法,并调用
func testReflect(b interface{})  {
	rVal := reflect.ValueOf(b).Elem()
	rType := reflect.TypeOf(b).Elem()

	//判断是否是结构体在进行下一步操作
	if rType.Kind() != reflect.Struct{
		fmt.Println("该类型不是结构体。所以无法获取字段及其方法。")
	}

	//获取字段数量
	numField := rVal.NumField()
	fmt.Printf("该结构体有%d个字段\n",numField)
	//遍历字段
	for i := 0; i < numField; i++ {
		//获取字段值、标签值
		rFieldTag := rType.Field(i).Tag.Get("json")
		if rFieldTag != "" {
			fmt.Printf("结构体第 %v 个字段值:%v ," +
				"Tagjson名为:%v\n",i,rVal.Field(i),rFieldTag)
		}
	}

	//调用方法(方法顺序 按照ACSII码排序)
	rVal.Method(0).Call(nil)
	rVal.Method(1).Call(nil)

	//参数也需要以 Value 的切片 传入
	params  := make([]reflect.Value ,3)
	params[0] = reflect.ValueOf("hhhh")
	params[1] = reflect.ValueOf(28)
	params[2] = reflect.ValueOf(99.9)
	rVal.Method(2).Call(params)

	rVal.Method(1).Call(nil)
}

func main() {
	stu := Student{
		Name: "莉莉安",
		Sex: "f",
		Age: 19,
		Sal: 98.5,
	}

	//调用编写的函数并输出
	testReflect(&stu)
	fmt.Println("主函数输出结构体 Student :",stu)
}

案例来源
案例2
请编写一个案例,演示对(基本数据类型/结构体类型、interface{}、reflect.Value)进行反射的基本操作

package main 
import (
	"reflect"
	"fmt"
)

//专门演示反射
func reflectTest01(b interface{}) {
	//通过反射获取的传入的变量的 type , kind, 值
	//1. 先获取到 reflect.Type 
	rTyp := reflect.TypeOf(b) 
	fmt.Println("rType=", rTyp)
	
	//2. 获取到 reflect.Value 
	rVal := reflect.ValueOf(b)
	n2 := 2 + rVal.Int() 
	fmt.Println("n2=", n2)
	fmt.Printf("rVal=%v rVal type=%T\n", rVal, rVal)
	
	//下面我们将 rVal 转成 interface{} 
	iV := rVal.Interface()
	//将 interface{} 通过断言转成需要的类型
	num2 := iV.(int) 
	fmt.Println("num2=", num2)
}


//专门演示反射[对结构体的反射] 
func reflectTest02(b interface{}) {
	//通过反射获取的传入的变量的 type , kind, 值
	//1.  先获取到 reflect.Type
	rTyp := reflect.TypeOf(b) 
	fmt.Println("rType=", rTyp)
	
	//2. 获取到 reflect.Value 
	rVal := reflect.ValueOf(b)
	
	//下面我们将 rVal 转成 interface{} 
	iV := rVal.Interface()
	fmt.Printf("iv=%v iv type=%T \n", iV, iV)
	
	//将 interface{} 通过断言转成需要的类型
	//这里,我们就简单使用了一带检测的类型断言.
	//同学们可以使用 swtich 的断言形式来做的更加的灵活
	stu, ok := iV.(Student) 
	if ok {
		fmt.Printf("stu.Name=%v\n", stu.Name)
	}
}


type Student struct { 
	Name string 
	Age int
}
type Monster struct { 
	Name string
	Age int
}

func main() {
	//请编写一个案例,
	//演示对(基本数据类型、interface{}、reflect.Value)进行反射的基本操作
	
	//1.  先定义一个 int
	// var num int = 100
	// reflectTest01(num)
	
	//2. 定义一个 Student 的实例
	stu := Student{ 
		Name : "tom", 
		Age : 20,
	}
	reflectTest02(stu)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值