给一个结构体添加“static”函数。

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

Adding "static" functions to a struct

问题

encoding/base64encoding/hex几乎支持相同的一组函数,但是base64使用基于类的编码器,而hex在顶层导出方法。是否有一种简单的方法来创建一个包装器,使得你可以使用抽象的编码接口来处理hex?更一般地说,是否有一种方法可以实现将方法绑定到结构体上的等效操作?(例如,SomeStruct.Encode = hex.Encode

到目前为止,我不得不在一个名为hexEncoder的结构体上定义与hex函数具有相同签名的函数。我创建了这样一个接口:

  1. type Encoding interface {
  2. Decode(dst, src []byte) (n int, err error)
  3. DecodedLen(n int) int
  4. Encode(dst, src []byte) // base64 返回空,hex 返回 int
  5. EncodedLen(n int) int
  6. }

这个接口与base64.StdEncoding完美配合,但是我不清楚如何包装hex的方法。我创建了一个空的hexEncoder结构体:

  1. // 包装 hex 编码/解码,以便可以与 base64 编码互换使用
  2. type hexEncoder struct {}
  3. func (h hexEncoder) Decode(dst, src []byte) (n int, err error) {
  4. return hex.Decode(dst, src)
  5. }
  6. func (h hexEncoder) DecodedLen(n int) int {
  7. return hex.DecodedLen(n)
  8. }
  9. func (h hexEncoder) Encode(dst, src []byte) {
  10. hex.Encode(dst, src) // 不返回 int,以匹配 Encoding
  11. }
  12. func (h hexEncoder) EncodedLen(n int) int {
  13. return hex.EncodedLen(n)
  14. }

这个方法可以工作,但是有很多额外的样板代码(实际上只需要包装hex.Encode)。有没有更好的方法来做到这一点?最终的目标是能够在编码/解码时可以互换使用hexbase64,就像下面这样:

  1. func convert(src []byte, decoder Encoding, encoder Encoding) ([]byte, error) {
  2. temp := make([]byte, decoder.DecodedLen(len(src)))
  3. n, err := decoder.Decode(temp, src)
  4. if err != nil {
  5. return temp, err
  6. }
  7. dst := make([]byte, encoder.EncodedLen(len(src)))
  8. encoder.Encode(dst, temp[:n])
  9. return dst, nil
  10. }
英文:

encoding/base64 and encoding/hex both support nearly the same set of functions, but base64 uses a class-based encoder, whereas hex exports the methods at the top level. Is there a simple way to create a wrapper around hex so that you can work with an abstracted encoding interface? More generally, is there a way to do the equivalent of binding a method to a struct? (e.g., SomeStruct.Encode = hex.Encode)

So far, I had to define functions on a hexEncoder struct with the same signature as the hex functions. I created an interface like this:

  1. type Encoding interface {
  2. Decode(dst, src []byte) (n int, err error)
  3. DecodedLen(n int) int
  4. Encode(dst, src []byte) // base64 returns nothing, hex returns int
  5. EncodedLen(n int) int
  6. }

which works perfectly with base64.StdEncoding, but I wasn't clear on how to wrap the hex methods. I created an empty struct for hex:

  1. // wrap hex encoding/decoding so that it can be used interchangeably with base64 encoding
  2. type hexEncoder struct {}
  3. func (h hexEncoder) Decode(dst, src []byte) (n int, err error) {
  4. return hex.Decode(dst, src)
  5. }
  6. func (h hexEncoder) DecodedLen(n int) int {
  7. return hex.DecodedLen(n)
  8. }
  9. func (h hexEncoder) Encode(dst, src []byte) {
  10. hex.Encode(dst, src) // don't return the int to match Encoding
  11. }
  12. func (h hexEncoder) EncodedLen(n int) int {
  13. return hex.EncodedLen(n)
  14. }

This works, but it's a bunch of extra boiler plate (where all that really needs to be wrapped is hex.Encode). Is there a better way to do this? Ultimately, the goal is to be able to use hex and base64 interchangeably with encoding/decoding, like in something like this:

  1. func convert(src []byte, decoder Encoding, encoder Encoding) ([]byte, error) {
  2. temp := make([]byte, decoder.DecodedLen(len(src)))
  3. n, err := decoder.Decode(temp, src)
  4. if err != nil {
  5. return temp, err
  6. }
  7. dst := make([]byte, encoder.EncodedLen(len(src)))
  8. encoder.Encode(dst, temp[:n])
  9. return dst, nil
  10. }

答案1

得分: 2

不,目前没有更好的方法来实现将接口分派到另一个包中的函数,而且说实话,我真的无法想象出更好的方法会是什么样子。

你在包装器中所说的是:

  1. type myType struct{}
  2. func (myType) WhenCalledLikeThis() { DoThat() }

这似乎是最佳的方式。它不需要任何后备内存,允许对命名和返回值进行轻微更改(就像你对Encode所做的那样),并且通过单个调用进行分派。

英文:

No, there is no better way to implement an interface that dispatches to functions in another package, and to be honest I cannot really imagine how a better way would look like.

What you're saying in that wrapper is:

  1. type myType struct{}
  2. func (myType) WhenCalledLikeThis() { DoThat() }

Which seems optimal. It doesn't need any backing memory, allows slight changes in naming and return values (as you've done for Encode), and dispatches with a single call.

huangapple
  • 本文由 发表于 2013年9月3日 08:46:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/18582522.html
匿名

发表评论

匿名网友

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

确定