如何在Go中嵌入第三方类型?

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

How to embed third party types in Go?

问题

在我的应用程序中,使用了 Decimal 包 github.com/shopspring/decimal

为了在 decimal.Decimal 类型上编写自定义函数,我创建了自己的 Decimal 类型并嵌入了 decimal.Decimal

type Decimal struct {
    decimal.Decimal
}

这很好用,现在我可以在 Decimal 对象上访问 decimal.Decimal 的方法:

a := Decimal{decimal.NewFromFloat(1.0)}
b := Decimal{a.Neg()}

一些 decimal.Decimal 的方法需要一个 decimal.Decimal 类型的参数,例如:

c := Decimal{a.Add(b)}

上面的代码无法编译,因为出现了错误:cannot use b (variable of type Decimal) as decimal.Decimal value in argument to a.Add

我尝试将 Decimal 转换为 decimal.Decimal

c := Decimal{a.Add((decimal.Decimal)(b))}

上面的代码无法编译,因为出现了以下错误:

cannot convert b (variable of type Decimal) to decimal.Decimal

**问题:**如何以一种方式扩展/嵌入第三方类型,使得可以使用“父类”方法,并且可以将扩展类型用作需要父类类型参数的方法的参数?

英文:

In my application, the Decimal package github.com/shopspring/decimal is used.

In order to write custom functions on the decimal.Decimal type, I have created my own Decimal type and embedded decimal.Decimal:

type Decimal struct {
	decimal.Decimal
}

This works great, and I can now access decimal.Decimal methods on Decimal object:

a := Decimal{decimal.NewFromFloat(1.0)}
b := Decimal{a.Neg()}

Some of decimal.Decimal methods requires an argument of type decimal.Decimal, f.ex:

c := Decimal{a.Add(b)}

The above line cannot compile because of error: cannot use b (variable of type Decimal) as decimal.Decimal value in argument to a.Add

I have tried to convert Decimal to decimal.Decimal:

c := Decimal{a.Add((decimal.Decimal)(b))}

The above code would not compile due to below error:

cannot convert b (variable of type Decimal) to decimal.Decimal

Question: How to extend/embed a third party type in a way that allows the use of "parent" methods and can use the extended type as argument in methods that requires argument of parents type?

答案1

得分: 2

一个声明了类型但没有显式字段名的字段被称为嵌入字段。嵌入字段必须指定为类型名T或指向非接口类型名*T的指针,并且T本身不能是指针类型。未限定的类型名充当字段名

因此,一个快速而简单的解决方案是使用"未限定的类型名"来访问该字段。

_ = Decimal{a.Add(b.Decimal)}

然而,如果你希望在使用新类型时获得更无缝的体验,那么你唯一的选择就是重新声明需要原始类型的方法,并在其中使用新类型。这些重新声明的方法只需要是简单的包装器,将一个实例的嵌入字段传递给另一个实例的嵌入字段的方法。例如:

type Time struct {
	time.Time
}

func (t Time) In(loc *time.Location) Time {
	return Time{t.Time.In(loc)}
}

func (t Time) Equal(u Time) bool {
	return t.Time.Equal(u.Time)
}
英文:

> A field declared with a type but no explicit field name is called an embedded field. An embedded field must be specified as a type name T or as a pointer to a non-interface type name *T, and T itself may not be a pointer type. The unqualified type name acts as the field name.

So a quick and dirty solution would be to simply access the field using the "unqualified type name".

_ = Decimal{a.Add(b.Decimal)}

If, however, you're looking for a more seamless experience when using the new type, then your only option is to redeclare the methods that require the original type and use the new type in its place. These redeclared methods need only be simple wrappers that pass the embedded field of one instance to the method of the embedded field of the other instance. For example:

type Time struct {
	time.Time
}

func (t Time) In(loc *time.Location) Time {
	return Time{t.Time.In(loc)}
}

func (t Time) Equal(u Time) bool {
	return t.Time.Equal(u.Time)
}

huangapple
  • 本文由 发表于 2023年1月9日 21:12:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/75057783.html
匿名

发表评论

匿名网友

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

确定