前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言如何利用反射机制 动态调用结构体中的方法和属性

Go语言如何利用反射机制 动态调用结构体中的方法和属性

原创
作者头像
Mandy的名字被占用了
发布2024-05-14 19:19:43
1030
发布2024-05-14 19:19:43
举报

相信做个PHP的同学,在很多时候都使用过如下的方式去调用一个类中的方法,或者某个属性。

代码语言:php
复制
$method = "show";
$object = new A();
$object->$method();

在PHP中使用这种写法是完全没有问题的,但是做Go这种静态语言中,在编译阶段就会发生错误,因此在Go语言中不能使用该方式调用,而需要反射机制来实现。

在实际的项目开发中,很多时候我们要实现某种功能,可能需要对接不同的平台,每个平台的接口肯定是不同的。但为了方便系统的维护、扩展。都会把不同平台的实现方式封装成一个扩展,然后在调用时通过一个工厂类去处理调用具体的扩展,只要保证每一个扩展中的返回参数格式一致就可以了。至于每一个扩展具体是怎么实现的,调用方根本不用关心,只需要关心入参和出参即可

为了保持每一个扩展中的返回参数方法,格式都保持一致,后期易于扩展。一般我们会封装一个接口,几口定义好提供给外部的方法,方法的接收参数和返回参数。如下示例代码:

代码语言:php
复制
interface A
{
    public function show(): string;
    public function run(): array;
}

class B implements A
{
    public function show(): string
    {
        return __CLASS__ . __METHOD__ . __LINE__;
    }

    public function run(): array
    {
        return [
            "class" => __CLASS__,
            "method" => __METHOD__,
            "line" => __LINE__,
        ];
    }
}


class C implements A
{
    public function show(): string
    {
        return __CLASS__ . __METHOD__ . __LINE__;
    }

    public function run(): array
    {
        return [
            "class" => __CLASS__,
            "method" => __METHOD__,
            "line" => __LINE__,
        ];
    }
}


class D
{
    public function print(A $a, string $method)
    {
        print_r($a->$method());
    }
}

$d = new D;
// 动态设置调用的类以及类下的方法
$d->print(new B, "run");

看完上面的代码,在回过头去考虑在Go语言是否可以这样实现呢?

在Go语言中,要实现这样的操作,可以采用这样的思路,但是在调用的地方就不能这么写。因为Go语言属于编译型语言,发现找不到对应的方法,就会编译不通过。

因此,Go语言提供了一种机制在运行时更新变量和检查他们的值,调用它们的方法,但是在编译时并不知道这些变量的具体类型,这称为反射机制。

使用上面PHP的代码,我们用Go语言进行实现一次。

代码语言:go
复制
package main

import (
	"fmt"
	"reflect"
)

// 使用interface限定参数类型,动态调用struct中的方法、方法

type A1 interface {
	Show1(name string)
}

type B1 struct {
	Name1   string
	Age1    uint
	Sex1    string
	IsOver1 bool
}

func (b1 B1) Show1(name string) {
	fmt.Println(reflect.TypeOf(b1), name)
}

func (b1 B1) Run1() {
	fmt.Print("b1->Run1()")
}

type C1 struct {
}

func (c1 C1) Show1(name string) {
	fmt.Println(reflect.TypeOf(c1))
}

type D1 struct {
}

func (d1 D1) Run1(name string) {
	fmt.Println(reflect.TypeOf(d1))
}

func printShow(a A1, menthod string, args ...interface{}) {
	inputs := make([]reflect.Value, len(args))
	for i, _ := range args {
		inputs[i] = reflect.ValueOf(args[i])
	}
	// 动态调用struct中的方法
	reflect.ValueOf(a).MethodByName(menthod).Call(inputs)

	// 动态调用struct中的属性
	fmt.Println("所有属性值", reflect.ValueOf(a).Elem())
	fmt.Println("指定属性值", reflect.ValueOf(a).Elem().FieldByName("IsOver1"))
}

func main() {
	// 使用此方式直接调用,
	printShow(&B1{}, "Show1")
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档