英文:
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 (
"net/url"
"reflect"
)
// 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 < 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"`
}
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 (
"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"`
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论