Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > go 结构体和反射

Golang中的结构体和反射示例详解

作者:O.0)O.O(0.O

文章介绍了Go语言中结构体的使用、结构体与JSON数据的转换以及反射机制,反射允许在运行时获取类型信息、动态调用方法、访问属性和构造对象,文章还提到了使用reflect包来获取和操作结构体的字段、方法、类型和值,本文结合实例代码介绍的非常详细,感兴趣的朋友一起看看吧

结构体

声明

// 声明一种新的类型 myint,是int的别名
type myint int
// 定义一个结构体:把多种基本数据类型组合到一起变成一个新的类型
type Book struct {
	title  string
	author string
	price  myint
}
func changeBook(book Book) {
	//传递的是值类型,所以修改的是副本,不会影响原来的变量
	book.price = 999
}
func changeBook1(book *Book) {
	// 指针类型可以修改结构体变量的值
	book.author = "新作者"
}
func main() {
	var a myint = 10
	fmt.Println("a =", a)
	fmt.Printf("type of a is %T\n", a)
	var book1 Book
	book1.title = "Go 语言"
	book1.author = "老子"
	book1.price = 299
	fmt.Println("book1 =", book1)
	fmt.Printf("type of book1 is %T\n", book1)
	changeBook(book1)
	fmt.Println("--------------")
	fmt.Println("book1 =", book1)
	changeBook1(&book1)
	fmt.Println("--------------")
	fmt.Println("book1 =", book1)
}
=================================================
PS D:\GoProject\firstGoProject> go run firstGoProject.go
a = 10
type of a is main.myint
book1 = {Go 语言 老子 299}
type of book1 is main.Book
--------------
book1 = {Go 语言 老子 299}
--------------
book1 = {Go 语言 新作者 299}

结构体的使用

import "fmt"
//如果类名首字母大写,表示其他包也可以访问
type Hero struct {
	//如果类的属性首字母大写,表示其他包也可以访问,否则只能在本包中访问
	Name  string
	Ad    int
	Level int
}
func (this Hero) GetName() string {
	return this.Name
}
func (this Hero) SetName(newName string) {
	//当前this是调用该方法的对象的拷贝
	this.Name = newName
}
func (this Hero) ShowInfo() {
	fmt.Println("hero = ", this)
}
func (this *Hero) SetName1(newName string) {
	//这里的this是指针类型,所以可以修改对象的值
	this.Name = newName
}
func main() {
	// create a Hero object
	hero := Hero{Name: "Alice", Ad: 100, Level: 10}
	var name = hero.GetName()
	fmt.Println("name = ", name)
	hero.ShowInfo()
	hero.SetName("Bob")
	hero.ShowInfo()
	hero.SetName1("Charlie")
	hero.ShowInfo()
}
-----------------------------------------------------
PS D:\GoProject\firstGoProject> go run firstGoProject.go
name =  Alice
hero =  {Alice 100 10}
hero =  {Alice 100 10}
hero =  {Charlie 100 10}

结构体和json数据的互相转换

import (
	"encoding/json"
	"fmt"
)
type Movie struct {
	Title  string   `json:"title"`      //结构体的标签
	Year   int      `json:"year"`
	Price  int      `json:"price"`
	Actors []string `json:"actors"`
}
func main() {
	movie := Movie{
		Title:  "The Dark Knight",
		Year:   2008,
		Price:  150,
		Actors: []string{"Christopher Nolan", "Robert Duvall"},
	}
	//编码的过程  结构体 --->  json
	jsonStr, err := json.Marshal(movie)
	if err != nil {
		fmt.Println("json marshal error", err)
	}
	fmt.Printf("jsonStr = %s\n", jsonStr)
	//解码的过程  json --->  结构体
	//jsonStr = {"title":"The Dark Knight","year":2008,"price":150,"actors":["Christopher Nolan","Robert Duvall"]}
	myMovie := Movie{}
	err = json.Unmarshal(jsonStr, &myMovie)
	if err != nil {
		fmt.Println("json unmarshal error", err)
		return
	}
	fmt.Printf("myMovie = %v\n", myMovie)
}
PS D:\GoProject\firstGoProject> go run firstGoProject.go
jsonStr = {"title":"The Dark Knight","year":2008,"price":150,"actors":["Christopher Nolan","Robert Duvall"]}
myMovie = {The Dark Knight 2008 150 [Christopher Nolan Robert Duvall]}

反射

反射(Reflection) 是指在程序运行时可以访问、检测和修改其自身状态或行为的一种能力。
具体来说,在面向对象编程中,反射允许程序:

反射机制允许程序在运行时获取类型信息并动态调用成员,而不需要在编译时确定具体的类或方法。

变量内置pair结构

一个变量中含有type  和  value ,称作pair

type分为 static type  和 concrete type,变量的type是两者中的一个(不能同时有两个type) 

import "fmt"
func main() {
	var a string
	//pair <type:static type(string), value:"Hello, World!">
	a = "Hello, World!"
	//pair <type:constant type, value: nil>
	var allType interface{}
	//pair <type:string, value:"Hello, World!">
	allType = a
	str, _ := allType.(string)
	fmt.Println(str)
}
-------------------------------------------------------
PS D:\GoProject\firstGoProject> go run firstGoProject.go
Hello, World!
import (
	"fmt"
	"io"
	"os"
)
func main() {
	//tty: pair<type: *os.File, value: "/dev/tty" 文件描述符>
	tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
	if err != nil {
		fmt.Println(err)
		return
	}
	//r: pair<type: ,value: >
	var r io.Reader
	//r: pair<type: *os.File, value: "/dev/tty" 文件描述符>
	r = tty
	//w: pair<type: ,value: >
	var w io.Writer
	//w: pair<type: *os.File, value: "/dev/tty" 文件描述符>
	w = r.(io.Writer)
	w.Write([]byte("Hello, world!\n")) // 向终端输出 "Hello, world!\n"
}
type Reader interface {
	ReadBook()
}
type Writer interface {
	WriteBook()
}
// 具体类型
type Book struct {
}
func (this *Book) ReadBook() {
	fmt.Println("Reading book...")
}
func (this *Book) WriteBook() {
	fmt.Println("Writing book...")
}
func main() {
	// 接口变量 b:pair<type:Book,value:book{}地址>
	b := &Book{}
	// 接口变量 r:pair<type:,value:>
	var r Reader
	//此时r的类型为nil
	fmt.Printf("r: %T\n", r)
	//r:pair<type:Book,value:book{}地址>
	r = b
	// 调用接口方法
	r.ReadBook()
	var w Writer
	w = r.(Writer)
	w.WriteBook()
}
-------------------------------------------------------------
PS D:\GoProject\firstGoProject> go run firstGoProject.go
r: <nil>
Reading book...
Writing book...

reflect包

获取字段的类型和值

import (
	"fmt"
	"reflect"
)
func reflectNum(arg interface{}) {
	fmt.Println("type :", reflect.TypeOf(arg))
	fmt.Println("value:", reflect.ValueOf(arg))
}
func main() {
	var num float64 = 3.14
	reflectNum(num)
}
----------------------------------------------
PS D:\GoProject\firstGoProject> go run firstGoProject.go
type : float64
value: 3.14

获取结构体字段、方法的名称、类型和值

import (
	"fmt"
	"reflect"
)
type User struct {
	Id   int
	Name string
	Age  int
}
func (this User) Call() {
	fmt.Println("user is called ..")
	fmt.Printf("%v\n", this)
}
func main() {
	user := User{1, "John", 25}
	DoFileAndMethod(user)
}
func DoFileAndMethod(input interface{}) {
	//获取input的类型
	inputType := reflect.TypeOf(input)
	fmt.Println("inputType is:", inputType.Name())
	//获取input的value
	inputValue := reflect.ValueOf(input)
	fmt.Println("inputValue is:", inputValue)
	//通过type获取里面的字段
	//1. 获取interface的reflect.Type,通过Type得到NumField,进行遍历
	//2. 得到每个field,数据类型
	//3. 通过filed有一个Interface()方法等到 对应的value
	for i := 0; i < inputType.NumField(); i++ {
		field := inputType.Field(i)
		value := inputValue.Field(i).Interface()
		fmt.Printf("field = %s,type = %v, value = %v\n", field.Name, field.Type, value)
	}
	fmt.Println("--------------------", inputType.NumMethod())
	//通过type获取里面的方法,调用
	for i := 0; i < inputType.NumMethod(); i++ {
		m := inputType.Method(i)
		fmt.Printf("%s,%v\n", m.Name, m.Type)
	}
}
PS D:\GoProject\firstGoProject> go run firstGoProject.go
inputType is: User
inputValue is: {1 John 25}
field = Id,type = int, value = 1        
field = Name,type = string, value = John
field = Age,type = int, value = 25      
-------------------- 1
Call,func(main.User)

解析结构体标签Tag

import (
	"fmt"
	"reflect"
)
type resume struct {
	Name string `info:"name" doc:"我的名字"`
	Sex  string `info:"sex" doc:"我的性别"`
}
func findTag(str interface{}) {
	t := reflect.TypeOf(str).Elem()
	for i := 0; i < t.NumField(); i++ {
		taginfo := t.Field(i).Tag.Get("info")
		tagdoc := t.Field(i).Tag.Get("doc")
		fmt.Println("info:", taginfo, "doc:", tagdoc)
	}
}
func main() {
	var re resume
	findTag(&re)
}
PS D:\GoProject\firstGoProject> go run firstGoProject.go
info: name doc: 我的名字
info: sex doc: 我的性别

到此这篇关于Golang的结构体和反射的文章就介绍到这了,更多相关go 结构体和反射内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文