Go语言笔记----基础语法

x33g5p2x  于2022-04-02 转载在 其他  
字(19.5k)|赞(0)|评价(0)|浏览(687)

局部变量,全局变量,多变量声明

代码简单演示:

package main

import "fmt"

//main方法调用前会被调用
func init() {
	fmt.Println("init方法会在main方法调用前会被调用")
}

//声明全局变量 方法一,二,三是可以的,但是方法四不行
var g1 int
var g2 int =520
var g3 =521
//方法四声明全局变量会报错
//:=只能用在函数体内使用
//g4:=1000

func main() {
	fmt.Println("=============================")
	fmt.Println("方法一:声明一个变量,默认值为0")
	var a int
	//Println是换行输出
	fmt.Println("a= ", a)
	//Printf是格式化输出--需要手动换行
	fmt.Printf("type of a= %T \n", a)
	fmt.Println("=============================")

	fmt.Println("方法二: 声明一个变量,初始化一个值")
	var b int = 100
	fmt.Println("b= ", b)
	fmt.Printf("type of b= %T \n", b)
	fmt.Println("=============================")

	fmt.Println("方法二: 声明一个变量,初始化一个值")
	var s string = "大忽悠";
	fmt.Printf("type of s= %T\n", s)
	fmt.Println("=============================")

	fmt.Println("方法三:在初始化的时候,省略数据类型,通过值自动匹配当前的变量的数据类型")
	var c = 100
	fmt.Println("c= ", c)
	fmt.Printf("type of c= %T \n", c)
	fmt.Println("=============================")

	fmt.Println("方法四: 省去var关键字,直接自动匹配")
	e := "哈哈哈哈"
	fmt.Println("e =",e)
	fmt.Printf("type of e= %T\n",e)
	fmt.Println("=============================")

	fmt.Println("方法四: 省去var关键字,直接自动匹配")
	f := 3.14
	fmt.Println("f =",f)
	fmt.Printf("type of f= %T\n",f)
	fmt.Println("=============================")

	fmt.Println("全局变量输出测试: g1=",g1," g2=",g2," g3=",g3)
	fmt.Println("=============================")

	//声明多个变量
	var xx,yy int =100,200
	fmt.Println("同时声明多个类型相同的变量: xx=",xx," yy=",yy)
    var kk,ll=300,"呜呜呜"
    fmt.Println("同时声明多个类型不同的变量: kk=",kk," ll=",ll)

	fmt.Println("=============================")

    fmt.Println("多行的变量声明测试: ")
    var (
    	aa int =100
    	bb bool=true
	)
    fmt.Println("aa= ",aa," bb=",bb)
}

输出结果:

init方法会在main方法调用前会被调用
=============================
方法一:声明一个变量,默认值为0
a=  0
type of a= int 
=============================
方法二: 声明一个变量,初始化一个值
b=  100
type of b= int 
=============================
方法二: 声明一个变量,初始化一个值
type of s= string
=============================
方法三:在初始化的时候,省略数据类型,通过值自动匹配当前的变量的数据类型
c=  100
type of c= int 
=============================
方法四: 省去var关键字,直接自动匹配
e = 哈哈哈哈
type of e= string
=============================
方法四: 省去var关键字,直接自动匹配
f = 3.14
type of f= float64
=============================
全局变量输出测试: g1= 0  g2= 520  g3= 521
=============================
同时声明多个类型相同的变量: xx= 100  yy= 200
同时声明多个类型不同的变量: kk= 300  ll= 呜呜呜
=============================
多行的变量声明测试: 
aa=  100  bb= true

const与iota

package main

import "fmt"

//const定义枚举类型
const(
	SUCCESS=200 
	NOT_FOUND=404
	ERROR=500
)

const(
	//可以在const()添加一个关键字iota,每行的iota都会增加1,第一行的iota默认为0
	ZERO=iota //iota=0
	FIRST     //iota=1
	SECOND    //iota=2
	THREE    //iota=3   
)

const (
	a,b =iota+1,iota+2 //iota=0,a=iota+1,b=iota+2,a=1,b=2
	c,d                //iota=1,c=iota+1,d=iota+2,c=2,d=3
	e,f                //iota=2,e=iota+1,f=iota+2,e=3,f=4
	
	g,h =iota*2,iota*3  //iota=3,g=iota*2,h=iota*3,g=6,h=9
	i,k                //iota=4,i=iota*2,k=iota*3 ,i=8,k=12
)
	
func main() {
	//常量---只读
	const len int =10;
	
	fmt.Println("len= ",len)
	
	fmt.Println("SUCCESS: ",SUCCESS)
	fmt.Println("NOT_FOUND: ",NOT_FOUND)
	fmt.Println("ERROR: ",ERROR)
	
	fmt.Println("a= ",a," b= ",b)
	fmt.Println("c= ",c," d= ",d)
	fmt.Println("e= ",e," f= ",f)

	fmt.Println("g= ",g," h= ",h)
	fmt.Println("i= ",i," k= ",k)
	
	//iota只能够配合const()一起使用,iota在const()才有累加效果
 	//var temp int=iota;
}

函数多返回值

package main

import "fmt"

//函数返回一个值
func foo1(a string,b int) int{
   fmt.Println("a= ",a)
   fmt.Println("b= ",b)

   c:=100

   return c
}

//返回多个值,匿名的
func fool2(a string)(int,int){
	fmt.Println("a= ",a)
	return 666,777
}

//返回多个值,有形参名称的
func fool3(a string)(r1 string, r2 int){
	fmt.Println("a= ",a)
	//给有名称的返回值变量赋值
	r1="大忽悠"
	r2=100
	return
}

func fool4(a string)(r1,r2 int){
	fmt.Println("a= ",a)
	//对于形参a和返回值变量r1,r2来说,他们的生命周期被局限在当前方法体内
	//但是对于返回值变量r1和r2来说,如果不进行赋值,默认为0
	fmt.Println("r1= ",r1," r2= ",r2)
	//给有名称的返回值变量赋值
	r1=520
	r2=100
	return
}

func main() {
	fmt.Println("foo1函数返回一个值: ",foo1("大 fu you",100))
	fmt.Println("----------------------------------------------")

	ret1,ret2:=fool2("哈哈哈2")
	fmt.Println("fool2函数有多个返回值,ret1= ",ret1," ret2= ",ret2)
	fmt.Println("----------------------------------------------")

	ret3,ret4:=fool3("哈哈哈3")
	fmt.Println("fool3函数有多个返回值,ret3= ",ret3," ret4= ",ret4)
	fmt.Println("----------------------------------------------")

	ret5,ret6:=fool4("哈哈哈4")
	fmt.Println("fool4函数有多个返回值,ret5= ",ret5," ret6= ",ret6)
	fmt.Println("----------------------------------------------")

}

init函数与import导包

导包测试:

package handle

import "fmt"

func init()  {
	fmt.Println("afterHandle执行初始化逻辑")
}

func AfterHandle(){
	fmt.Println("方法执行后的拦截逻辑.....")
}
package handle

import "fmt"

func init()  {
	fmt.Println("beforeHandle执行初始化逻辑")
}

func BeforeHandle() {
	fmt.Println("方法执行前的拦截逻辑.....")
}

导入handle包:

package main

import (
	"fmt"
	"handle"
)

func main() {
	handle.BeforeHandle()
	fmt.Println("哈哈哈哈")
	handle.AfterHandle()
}

结果:

包内方法名大小写区别

package handle

import "fmt"

func init()  {
	fmt.Println("beforeHandle执行初始化逻辑")
}

//当前函数名大写,表示当前函数对外开放,别的包只要导入了该包,便可以调用这个函数
//如果当前函数名小写,表示当前函数只能在当前包内被调用
func BeforeHandle() {
	fmt.Println("方法执行前的拦截逻辑.....")
}

import匿名及别名导包方式

匿名导入:

package main

import (
	"fmt"
	_"handle"
)

func main() {
	fmt.Println("哈哈哈哈")
}

别名导入:

package main

import (
	"fmt"
	myhandle "handle"
)

func main() {
	myhandle.BeforeHandle()
	fmt.Println("哈哈哈哈")
	myhandle.AfterHandle()
}

全部导入本包: 这种方法在多个包的情况下容易产生方法名冲突的问题

package main

import (
	"fmt"
	. "handle"
)

func main() {
	BeforeHandle()
	fmt.Println("哈哈哈哈")
	AfterHandle()
}

defer语句调用顺序

defer关键字的功能类似于c++的析构函数,用defer关键字声明的函数,会在当前方法执行结束后被执行,并且执行顺序类似于栈的先进后出关系

先声明的方法defer方法先入栈,因此后执行

package main

import "fmt"

func func1()  {
	fmt.Println("A")
}

func func2()  {
	fmt.Println("B")
}

func func3()  {
	fmt.Println("C")
}
func main(){
	defer func1()
	fmt.Println("hhh")
	defer func2()
	defer func3()
}

当defer和return同时出现,return先执行,defer后执行

package main

import "fmt"

func func1()  {
	fmt.Println("A")
}

func func2()  int{
	fmt.Println("B")
    return 0;
}

func func3() int {
	fmt.Println("C")
	defer func1()
	return func2();
}

func main(){
	func3()
}

数组

package main

import "fmt"

//只能接受长度为8的固定数组
//在go语言中,所有的变量都是值传递
func printArr(arr [8]int){
	arr[0]=520
	fmt.Println("函数中输出传入后修改的数组: ")
	for index, val := range arr {
		fmt.Println("index: ",index," val: ",val)
	}
}

func main() {
	//固定长度的数组
	var arr1 [10]int;
	fmt.Println("打印输出arr1数组: ");
	for i:=0; i<len(arr1) ;i++  {
		fmt.Print(arr1[i]," ")
	}
	fmt.Println()
	fmt.Println("--------------------------------------------")
	arr2:=[8]int{1,2,3,4,5}
	//下面arr2的输出,也可以验证这里是数组值传递
	printArr(arr2)
	for index, val := range arr2 {
		fmt.Println("当前遍历索引为: ",index," 当前索引对应的值为: ",val)
	}

	fmt.Println("查看数组的类型:")
	fmt.Printf("arr1数组的类型为: %T\n",arr1)
	fmt.Printf("arr2数组的类型为: %T\n",arr2)
}

切片—动态数组

//这里拿到的是数组的指针
func printArr(arr []int){
	arr[0]=520
	fmt.Println("函数中输出传入后修改的数组: ")
	for index, val := range arr {
		fmt.Println("index: ",index," val: ",val)
	}
}

func main() {
	//动态数组---切片---slice
	arr2:=[]int{1,2,3,4,5}
	//动态数组就是执行这块数组内存的一个指针引用
	//因此这里函数传递的是指向这块内存的一个指针引用
	printArr(arr2)
	for index, val := range arr2 {
		fmt.Println("当前遍历索引为: ",index," 当前索引对应的值为: ",val)
	}
}

动态数组在传参上是引⽤传递,⽽且不同元素⻓度的动态数组他们的形参是⼀致。

动态数组

package main

import "fmt"

func main() {
	fmt.Println("声明slcie1是一个切片,并且初始化,默认值为1,2,3 长度为3: ")
	slice1 := []int{1,2,3}
	fmt.Println(slice1)
	fmt.Println("----------------------------")

	fmt.Println("声明slice2是一个切片,但是并没有给slice分配空间")
    var slice2 []int;
	fmt.Println(slice2)
	fmt.Println("----------------------------")

	fmt.Println("给slice2开辟三个空间,默认值为0: ")
	slice2=make([]int,3)
	fmt.Println(slice2)
	fmt.Println("----------------------------")

	fmt.Println("声明slice3是一个切片,同时给slice3分配三个空间,默认值为0")
	var slice3 []int=make([]int,3);
	fmt.Println(slice3)
	fmt.Println("----------------------------")

	fmt.Println("声明slice4是一个切片,同时给slice4分配空间,3个空间,通过:=推导出slice4是一个切片")
	slice4:=make([]int,3)
	slice4[0]=1
	slice4[1]=2
	slice4[2]=3
	fmt.Println(slice4)
	fmt.Println("----------------------------")

    fmt.Println("输出slice4切片的长度和详细信息(-v): ")
    fmt.Printf("len= %d,slice= %v\n",len(slice4),slice4)
	fmt.Println("----------------------------")

	fmt.Println("判断一个slice是否为0")
	if slice3 == nil{
		fmt.Println("slice3是一个空切片")
	}else {
		fmt.Println("slice3是有空间的")
	}

	var slice5 []int;
	if slice5 == nil{
		fmt.Println("slice5是一个空切片")
	}else {
		fmt.Println("slice5是有空间的")
	}

}

slice的截取和追加

package main

import "fmt"

func main() {
	//最后一个参数指定的是切片容量
	var nums=make([]int,3,5)
	fmt.Printf("切片长度= %d, 切片容量为= %d, 切片详细信息=%v \n",len(nums),cap(nums),nums)
}

len和cap有啥区别呢?—>看图

append追加元素

func main() {
	//最后一个参数指定的是切片容量
	var nums=make([]int,3,5)
	info(nums)
    fmt.Println("向nums切片追加一个元素1")
	nums=append(nums,1,2)
	info(nums)
}

func info(nums []int){
	fmt.Printf("切片长度= %d, 切片容量为= %d, 切片详细信息=%v \n",len(nums),cap(nums),nums)
}

如果此时在追加一条数据呢?

显然会扩容,每次扩容为当前cap两倍的大小

截取元素

package main

import "fmt"

func main() {
	//创建切片
	nums:=[]int{1,2,3,4,5,6,7}
	info(nums)
	//切片截取---联想JAVA中String的subString功能
	info(nums[1:4])
    //默认下限为0
    info(nums[:3])
	//模式上限为len(s)
	info(nums[4:])
  
}

func info(nums []int){
	fmt.Printf("切片长度= %d, 切片容量为= %d, 切片详细信息=%v \n",len(nums),cap(nums),nums)
}

截取只是利用指针实现了逻辑上的分离,物理上还是一块内存,因此对截取后某部分的数据进行操作,会影响原切片

package main

import "fmt"

func main() {
	//创建切片
	nums:=[]int{1,2,3,4,5,6,7}
	info(nums)
	nums1:=nums[1:4]
    nums1[0]=520
    info(nums)
    info(nums1)

}

func info(nums []int){
	fmt.Printf("切片长度= %d, 切片容量为= %d, 切片详细信息=%v \n",len(nums),cap(nums),nums)
}

如何实现深拷贝呢?---->copy函数

package main

import "fmt"

func main() {
	//创建切片
	nums:=[]int{1,2,3,4,5,6,7}
	info(nums)
	s2:=make([]int,3)
	copy(s2,nums)
    info(s2)
	s2[0]=520
	info(nums)
	info(s2)
}

func info(nums []int){
	fmt.Printf("切片长度= %d, 切片容量为= %d, 切片详细信息=%v \n",len(nums),cap(nums),nums)
}

可以看出copy函数是深拷贝的实现

map

package main

import (
	"fmt"
)

func main() {
   //声明一个map类型,key是String,val是String
   var myMap1 map[string]string
   if myMap1==nil{
   	fmt.Println("myMap1是一个空map")
   }
   //在使用map前,需要先用make给map分配数据空间
   myMap1=make(map[string]string,10)

   myMap1["one"]="java"
   myMap1["two"]="c++"
   myMap1["three"]="python"

   fmt.Println(myMap1)

   fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")

   //第二种声明方式
   myMap2:=make(map[int]string);
   myMap2[0]="123"
   myMap2[1]="321"
   fmt.Println(myMap2)

	fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")

     //第三种声明方式
     myMap3:=map[int]string{
     	1 :"dhy",
     	2 :"ddhy",
     }
     fmt.Println(myMap3)
}

map的基本使用

package main

import "fmt"

//这里传递的是map的引用
func printMap(map1 map[string]string){
	//遍历元素
	for key, val := range map1 {
		fmt.Print(" key= ",key)
		fmt.Print(" val= ",val)
		fmt.Println()
	}
	fmt.Println("-------------------")
}

func main() {
    map1:=make(map[string]string)

    //添加元素
    map1["China"]="BeiJing"
	map1["Japan"]="Tokyo"
	map1["USA"]="NewYork"

	printMap(map1)

	//删除元素
	delete(map1,"China")

	printMap(map1)

	//修改元素
	map1["USA"]="DC"

	printMap(map1)

}

面向对象特征

struct结构体

package main

import "fmt"

//声明一种行的数据类型myint,是int的一个别名
type myint int

//定义一个结构体
type Book struct {
	title string
	auth string
}

//值传递
func changeBook(book Book){
	book.auth="大忽悠";
}

//地址传递
func changeBook1(book *Book){
	book.auth="大忽悠";
}

func main() {
    var tempVal myint=100
    fmt.Println("tempVal=",tempVal)
    fmt.Println("--------------------")

    var book Book
    book.title="Go语言圣经"
    book.auth="不知道"

    fmt.Printf("%v\n",book)
	fmt.Println("--------------------")

    //值传递
    changeBook(book)
	fmt.Printf("%v\n",book)
	fmt.Println("--------------------")

    //地址传递
	changeBook1(&book)
	fmt.Printf("%v\n",book)
	fmt.Println("--------------------")
}

面向对象类的表示和封装

package main

import "fmt"

//声明一种行的数据类型myint,是int的一个别名
type myint int

//定义一个结构体
//类名首字母大写,表示该属性对外可以访问,否则只能当前包类访问
type Book struct {
	title string
	auth string
}

//这里方法名首字母大小写同上
func (this Book) getTitle() string{
	return this.title
}

//值传递---this Book
func (this Book) setTitle(title string){
	//这里调用该方法对象的一个副本---拷贝
	this.title=title
}

//引用传递
func (this *Book) setTitle1(title string){
	this.title=title
}


func (this Book) show() {
	fmt.Println("书名: ",this.title," 作者: ",this.auth)
}

func main() {
	 book:=Book{title:"大忽悠历险记",auth:"大忽悠"}
	 book.show()

	 fmt.Println("值传递演示: ")
	 book.setTitle("小朋友历险记")
	 book.show()

	 fmt.Println("引用传递演示: ")
	book.setTitle1("小朋友历险记")
	 book.show()
}

类名、属性名、⽅法名 ⾸字⺟⼤写表示对外(其他包)可以访问,否则只能够在本包内访问

继承

package main

import "fmt"

type Huamn struct {
   name string
 	sex string
}

func (this *Huamn) Eat(){
	fmt.Println("Huamn.Eat()...")
}

func (this *Huamn) Walk(){
	fmt.Println("Huamn.Walk()...")
}

///
type SuperMan struct {
	Huamn //SuperMan类继承了HUMAN类的方法和属性

	level int
}

//重写了父类的方法
func (this *SuperMan) Eat(){
	fmt.Println("SuperMan.Eat()...")
}

func (this *SuperMan) Play(){
	fmt.Println("SuperMan.Play()...")
}

func (this SuperMan) Show(){
	fmt.Println("姓名: ",this.name," 性别: ",this.sex," 等级: ",this.level)
}

func main() {
	huamn:= Huamn{name: "大忽悠", sex: "未知"}
    huamn.Eat()
	huamn.Walk()

	//定义一个子类对象
	superMan:= SuperMan{Huamn{name: "小朋友", sex: "未知"}, 1000}
    superMan.Show()

	//方式二:
	var s SuperMan
	s.level=520
	s.name="大忽悠"
	s.sex="MAN"
	s.Show()
}

Go语言对烦人的权限做了删减,继承过程中没有啥子私有,公开,保护权限,只在是否对其他包公开这里做了权限限制,而且这一点是通过大小写完成的

多态

基本要素:

  • 有一个父类(有接口)
//本质是一个指针
type Animal interface {
	Sleep()
	GetColor() string
    GetType() string
}
  • 有子类实现了父类的全部接口方法
type Cat struct {
	color string
}

func (this *Cat) Sleep(){
	fmt.Println("Cat is Sleep")
}
func (this *Cat) GetColor() string{
	return this.color
}

func (this *Cat) GetType() string{
	return "Cat"
}


type Dog struct {
	color string
}

func (this *Dog) Sleep(){
	fmt.Println("Dog is Sleep")
}
func (this *Dog) GetColor() string{
	return this.color
}

func (this *Dog) GetType() string{
	return "Dog"
}
  • 父类类型的变量指针指向引用子类的具体数据变量
package main

import (
	"fmt"
)

//本质是一个指针
type Animal interface {
	Sleep()
	GetColor() string
    GetType() string
}

type Cat struct {
	color string
}

func (this *Cat) Sleep(){
	fmt.Println("Cat is Sleep")
}
func (this *Cat) GetColor() string{
	return this.color
}

func (this *Cat) GetType() string{
	return "Cat"
}

type Dog struct {
	color string
}

func (this *Dog) Sleep(){
	fmt.Println("Dog is Sleep")
}
func (this *Dog) GetColor() string{
	return this.color
}

func (this *Dog) GetType() string{
	return "Dog"
}

func test(animal Animal){
	animal.Sleep()
	color := animal.GetColor()
	getType := animal.GetType()
	fmt.Println("动物的颜色: ",color," 类型为: ",getType)
}

func main() {
	//接口的数据类型,父类指针
	var animal Animal
	animal=&Cat{"BLACK"}
	test(animal)

	animal=&Dog{"BROWN"}
	test(animal)
}

interface空接口万能类型与类型断言机制

package main

import "fmt"

//interface{}是万能类型
func myFunc(arg interface{}){
	fmt.Println("myFunc is called...")
	fmt.Println(arg)

	//interface{}该如何区分,此时引用的底层数据类型到底是什么
	//给interface{}提供"类型断言"的机制
	//返回的第二个参数是一个bool,表示当前断言的结果,第一个参数就是值
	val, ok := arg.(Book1)
    if !ok{
    	fmt.Println("arg is not Book1 type")
	}else{
		fmt.Println("arg is Book1 type,val= ",val)
		fmt.Printf("value type is %T\n",val)
	}
}

type Book1 struct {
	auth string
}

func main() {
	book := Book1{auth: "哈哈哈哈"}
    myFunc(book)
}

这里空接口类型指针,可以指向任何数据类型,因此可以看做是元数据类型,即所有数据类型都会实现的类型。这里可以类比JAVA中的Object

反射

变量的内置pair结构

package main

import "fmt"

func main() {
	var a string
	//pair<statictype:string , value: "abcd">
	a="abcd"

	//pair<type: value:>
	var allType interface{}
	//pair<concretetype:string , value: "abcd">
	allType=a

	//通过断言找到类型并打印对应的值
	s,_ := allType.(string)
   fmt.Println(s)
}

大家可以先理解一下

package main

import "fmt"

type Reader interface {
	ReadBook()
}

type Writer interface {
	WriterBook()
}

type Book2 struct {
}

func (this * Book2) ReadBook(){
	fmt.Println("read book")
}

func (this * Book2) WriterBook(){
	fmt.Println("writer book")
}

func main() {
    //b: pair<type:Book  value:book{}地址>
	b:=&Book2{}

	//r: pair<type: ,value: >
	var r Reader
	//r:pair<type:Book,value:book{}地址>
    r=b
    r.ReadBook()

    var w Writer
    //w: pair<type:Book,value:book{}地址>
    //这里是断言,返回断言后的值---也可以看做是类型转换
    //这里r和w具体的type是一致的
    w=r.(Writer)

    w.WriterBook()

}

反射reflect机制用法

reflect包

例子1:

package main

import (
	"fmt"
	"reflect"
)

func reflectTest(arg interface{}){
	fmt.Println("type: ",reflect.TypeOf(arg))
	fmt.Println("value: ",reflect.ValueOf(arg))
}

func main() {
	num:=1.23
	reflectTest(num)
}

例子2:

package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Name string
	Age int
}

func (this User) Show(){
	fmt.Println("name= ",this.Name," age= ",this.Age)
}

func reflectTest(arg interface{}){
	typeOf := reflect.TypeOf(arg)
	valueOf := reflect.ValueOf(arg)
	fmt.Println("type: ",typeOf)
	fmt.Println("value: ",valueOf)
	//通过type,获取里面的字段
	//1.获取interface的reflectType,通过Type得到NumField,进行遍历
	//2.得到每个Field,数据类型
	//3.通过filed有一个interface()方法得到对应的value
	for i:=0; i<typeOf.NumField();i++  {
		//输出字段类型相关的信息
		fieldType:=typeOf.Field(i)
        fmt.Println("当前field字段名: ",fieldType.Name," 字段所在包: ",fieldType.PkgPath,
        	" 字段类型: ",fieldType.Type," 字段索引: ",fieldType.Index,
        	"字段是否匿名: ",fieldType.Anonymous," 字段偏移量: ",fieldType.Offset,
        	" 字段的标签: ",fieldType.Tag)
		//输出字段值相关的信息
		//go语言里面struct里面变量如果大写则是public,如果是小写则是private的,private的时候通过反射不能获取其值
		fieldVal:=valueOf.Field(i).Interface()
		fmt.Println("当前字段的值为: ",fieldVal)
		fmt.Println("-----------------------------------------------------------")
	}

	//通过type获取里面的方法,调用
	method := typeOf.NumMethod()
	fmt.Println("方法数量: ",method)
	for j:=0;j<typeOf.NumMethod() ;j++  {
        m:=typeOf.Method(j)
        fmt.Println("方法名: ",m.Name," 方法类型: ",m.Type)
		fmt.Println("-----------------------------------------------------------")
	}

}

func main() {
	user := User{Name: "大忽悠", Age: 18}
	reflectTest(user)
}

结构体标签Tag

package main

import (
"fmt"
"reflect"
)

type User struct {
	Name string `info:"name"`
	Age int `info:"age"`
}

func (this User) Show(){
	fmt.Println("name= ",this.Name," age= ",this.Age)
}

func reflectTest(arg interface{}){
	typeOf := reflect.TypeOf(arg)
	for i:=0; i<typeOf.NumField();i++ {
		//输出字段类型相关的信息
		fieldType := typeOf.Field(i)
		fmt.Println("当前field字段名: ", fieldType.Name, " 字段所在包: ", fieldType.PkgPath,
			" 字段类型: ", fieldType.Type, " 字段索引: ", fieldType.Index,
			"字段是否匿名: ", fieldType.Anonymous, " 字段偏移量: ", fieldType.Offset,
			" 字段的标签: ", fieldType.Tag)
		//获取标签里面某个属性的值
		tag:= fieldType.Tag
		info := tag.Get("info")
		fmt.Println("标签中info对应的值为: ",info)
		fmt.Println("---------------------------------------------------------")
	}
}

func main() {
	user := User{Name: "大忽悠", Age: 18}
	reflectTest(user)
}

结构体标签Tag在Json中的应用

package main

import (
	"encoding/json"
	"fmt"
)

type Movie struct {
	Title string `json:"title"`
	Year int `json:"year"`
	Price int `json:"rmb"`
	Actors []string `json:"actors"`
}

func main() {
	movie := Movie{Title: "大忽悠", Year: 2023, Price: 1000000, Actors: []string{"大忽悠", "小朋友"}}

	//编码的过程: 将结构体转换为Json
	jsonStr,err := json.Marshal(movie)
	if err!=nil{
		fmt.Println("json format error : ",err)
		return
	}
	fmt.Printf("jsonStr = %s\n",jsonStr)

	//解码的过程: jsonstr--->结构体
	movie1 := Movie{}
	err = json.Unmarshal(jsonStr, &movie1)
   if err!=nil{
	   fmt.Println("json Unmarshal error : ",err)
	   return
   }
   fmt.Printf("movie1 %v\n",movie1)
}

相关文章