在Go语言中重用操作结构值的方法。

huangapple go评论90阅读模式
英文:

Reusing methods in go which operate on struct values

问题

我正在尝试在Go语言中在多个结构体之间共享一个方法。我不想在每个结构体中重新定义这个方法。

我知道在Go语言中,通过使用组合而不是继承来实现代码的可重用性。然而,我不知道如何在当前的用例中使用这个概念。我的代码如下:

package mypackage

import (
	"net/url"
	"reflect"
)

// 从查询结构体构建查询字符串
func (params ListShipmentsQuery) toQueryString() string {
	query := url.Values{}
	values := reflect.ValueOf(params)
	types := values.Type()
	for i := 0; i < values.NumField(); i++ {
		value := values.Field(i).Interface().(string)
		if value != "" {
			query.Add(types.Field(i).Tag.Get("url"), value)
		}
	}

	return query.Encode()
}

type ListShipmentsQuery struct {
	ShipmentId string `url:"shipment_id"`
	OrderId    string `url:"order_id"`
}

type ListProductsQuery struct {
	Sku  string `url:"sku"`
	Name string `url:"name"`
}

如何将相同的方法应用于ListProductsQuery结构体而不重复自己?该方法必须使用构成结构体的属性。

例如,在PHP中使用继承,我会这样做:

class Parent 
{
    public function toQueryString()
    {
        // 逻辑来获取属性并构建查询字符串
    }
}

class Child extends Parent {}

$c = new Child();
$query_string = $c->toQueryString();

我尝试通过组合实现另一个结构体,但我无法将“父结构体”的属性传递给具有共享方法的结构体。

英文:

I am trying to share a single method across multiple structs in go. I do not want to have to redefine the method across every struct.

I realise that code reusability in go is achieved by using composition over inheritance. However I have no idea how to use the concept in my current use case. My code is the following:

package mypackage

import (
	&quot;net/url&quot;
	&quot;reflect&quot;
)


// Build a query string from a query struct
func (params ListShipmentsQuery) toQueryString() string {
	query := url.Values{}
	values := reflect.ValueOf(params)
	types := values.Type()
	for i := 0; i &lt; values.NumField(); i++ {
		value := values.Field(i).Interface().(string)
		if value != &quot;&quot; {
			query.Add(types.Field(i).Tag.Get(&quot;url&quot;), value)
		}

	}

	return query.Encode()
}

type ListShipmentsQuery struct {
	ShipmentId string `url:&quot;shipment_id&quot;`
	OrderId string `url:&quot;order_id&quot;`
}

type ListProductsQuery struct {
	Sku string `url:&quot;sku&quot;`
	Name string `url:&quot;name&quot;`
}

How can I apply the same method to the ListProductsQuery struct without repeating myself? The method must use the properties that make up the struct.

For example in PHP using inheritance I would do:

class Parent 
{
    public function toQueryString()
    {
        // Logic to grab properties and build query string
    }
}

class Child {}

$c = new Child();
$query_string = $c.toQueryString();

I have tried implementing another struct via composition but I have no way of passing the "parent's" properties to the struct which will have the shared method.

答案1

得分: 3

这是一个使用泛型的示例,我仍然倾向于使用评论中建议的简单函数示例,但对于某些情况来说,这肯定是有用的:

package main

import (
	"fmt"
	"net/url"
	"reflect"
)

func main() {
	{

		p := Parent[ListShipmentsQuery]{}
		p.child.ShipmentId = "hi"
		p.child.OrderId = "hi"
		fmt.Println(p.toQueryString())
	}
	{

		p := Parent[ListProductsQuery]{}
		p.child.Sku = "hi"
		p.child.Name = "hi"
		fmt.Println(p.toQueryString())
	}
}

type Parent[C any] struct {
	child C
}

func (p *Parent[C]) toQueryString() string {
	query := url.Values{}
	values := reflect.ValueOf(p.child)
	types := values.Type()
	for i := 0; i < values.NumField(); i++ {
		value := values.Field(i).Interface().(string)
		if value != "" {
			query.Add(types.Field(i).Tag.Get("url"), value)
		}

	}
	return query.Encode()
}

type ListShipmentsQuery struct {
	ShipmentId string `url:"shipment_id"`
	OrderId    string `url:"order_id"`
}

type ListProductsQuery struct {
	Sku  string `url:"sku"`
	Name string `url:"name"`
}
英文:

here's an example using generics, I would still probably go for the simple function example suggested in the comments, but this is surely useful for certain cases:

package main

import (
	&quot;fmt&quot;
	&quot;net/url&quot;
	&quot;reflect&quot;
)

func main() {
	{

		p := Parent[ListShipmentsQuery]{}
		p.child.ShipmentId = &quot;hi&quot;
		p.child.OrderId = &quot;hi&quot;
		fmt.Println(p.toQueryString())
	}
	{

		p := Parent[ListProductsQuery]{}
		p.child.Sku = &quot;hi&quot;
		p.child.Name = &quot;hi&quot;
		fmt.Println(p.toQueryString())
	}
}

type Parent[C any] struct {
	child C
}

func (p *Parent[C]) toQueryString() string {
	query := url.Values{}
	values := reflect.ValueOf(p.child)
	types := values.Type()
	for i := 0; i &lt; values.NumField(); i++ {
		value := values.Field(i).Interface().(string)
		if value != &quot;&quot; {
			query.Add(types.Field(i).Tag.Get(&quot;url&quot;), value)
		}

	}
	return query.Encode()
}

type ListShipmentsQuery struct {
	ShipmentId string `url:&quot;shipment_id&quot;`
	OrderId    string `url:&quot;order_id&quot;`
}

type ListProductsQuery struct {
	Sku  string `url:&quot;sku&quot;`
	Name string `url:&quot;name&quot;`
}

huangapple
  • 本文由 发表于 2023年5月21日 21:59:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76300272.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定